RDMA/nes: Add a driver for NetEffect RNICs
Glenn Streiff [Tue, 5 Feb 2008 04:20:45 +0000 (20:20 -0800)]
Add a standard NIC and RDMA/iWARP driver for NetEffect 1/10Gb ethernet adapters.

Signed-off-by: Glenn Streiff <gstreiff@neteffect.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

17 files changed:
MAINTAINERS
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/hw/nes/Kconfig [new file with mode: 0644]
drivers/infiniband/hw/nes/Makefile [new file with mode: 0644]
drivers/infiniband/hw/nes/nes.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_cm.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_cm.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_context.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_hw.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_hw.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_nic.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_user.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_utils.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_verbs.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_verbs.h [new file with mode: 0644]

index da30a72..548df4b 100644 (file)
@@ -2681,6 +2681,16 @@ M:       James.Bottomley@HansenPartnership.com
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 
+NETEFFECT IWARP RNIC DRIVER (IW_NES)
+P:     Faisal Latif
+M:     flatif@neteffect.com
+P:     Glenn Streiff
+M:     gstreiff@neteffect.com
+L:     general@lists.openfabrics.org
+W:     http://www.neteffect.com
+S:     Supported
+F:     drivers/infiniband/hw/nes/
+
 NETEM NETWORK EMULATOR
 P:     Stephen Hemminger
 M:     shemminger@linux-foundation.org
index a193dfb..a5dc78a 100644 (file)
@@ -44,8 +44,8 @@ source "drivers/infiniband/hw/ipath/Kconfig"
 source "drivers/infiniband/hw/ehca/Kconfig"
 source "drivers/infiniband/hw/amso1100/Kconfig"
 source "drivers/infiniband/hw/cxgb3/Kconfig"
-
 source "drivers/infiniband/hw/mlx4/Kconfig"
+source "drivers/infiniband/hw/nes/Kconfig"
 
 source "drivers/infiniband/ulp/ipoib/Kconfig"
 
index 75f325e..ed35e44 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_INFINIBAND_EHCA)           += hw/ehca/
 obj-$(CONFIG_INFINIBAND_AMSO1100)      += hw/amso1100/
 obj-$(CONFIG_INFINIBAND_CXGB3)         += hw/cxgb3/
 obj-$(CONFIG_MLX4_INFINIBAND)          += hw/mlx4/
+obj-$(CONFIG_INFINIBAND_NES)           += hw/nes/
 obj-$(CONFIG_INFINIBAND_IPOIB)         += ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)           += ulp/srp/
 obj-$(CONFIG_INFINIBAND_ISER)          += ulp/iser/
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
new file mode 100644 (file)
index 0000000..2aeb7ac
--- /dev/null
@@ -0,0 +1,16 @@
+config INFINIBAND_NES
+       tristate "NetEffect RNIC Driver"
+       depends on PCI && INET && INFINIBAND
+       select LIBCRC32C
+       ---help---
+         This is a low-level driver for NetEffect RDMA enabled
+         Network Interface Cards (RNIC).
+
+config INFINIBAND_NES_DEBUG
+       bool "Verbose debugging output"
+       depends on INFINIBAND_NES
+       default n
+       ---help---
+         This option causes the NetEffect RNIC driver to produce debug
+         messages.  Select this if you are developing the driver
+         or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
new file mode 100644 (file)
index 0000000..3514851
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
+
+iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
new file mode 100644 (file)
index 0000000..7f8853b
--- /dev/null
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/highmem.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/iw_cm.h>
+
+#include "nes.h"
+
+#include <net/netevent.h>
+#include <net/neighbour.h>
+#include <linux/route.h>
+#include <net/ip_fib.h>
+
+MODULE_AUTHOR("NetEffect");
+MODULE_DESCRIPTION("NetEffect RNIC Low-level iWARP Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+int max_mtu = 9000;
+int nics_per_function = 1;
+int interrupt_mod_interval = 0;
+
+
+/* Interoperability */
+int mpa_version = 1;
+module_param(mpa_version, int, 0);
+MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
+
+/* Interoperability */
+int disable_mpa_crc = 0;
+module_param(disable_mpa_crc, int, 0);
+MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
+
+unsigned int send_first = 0;
+module_param(send_first, int, 0);
+MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
+
+
+unsigned int nes_drv_opt = 0;
+module_param(nes_drv_opt, int, 0);
+MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
+
+unsigned int nes_debug_level = 0;
+module_param_named(debug_level, nes_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug output level");
+
+LIST_HEAD(nes_adapter_list);
+LIST_HEAD(nes_dev_list);
+
+atomic_t qps_destroyed;
+atomic_t cqp_reqs_allocated;
+atomic_t cqp_reqs_freed;
+atomic_t cqp_reqs_dynallocated;
+atomic_t cqp_reqs_dynfreed;
+atomic_t cqp_reqs_queued;
+atomic_t cqp_reqs_redriven;
+
+static void nes_print_macaddr(struct net_device *netdev);
+static irqreturn_t nes_interrupt(int, void *);
+static int __devinit nes_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nes_remove(struct pci_dev *);
+static int __init nes_init_module(void);
+static void __exit nes_exit_module(void);
+static unsigned int ee_flsh_adapter;
+static unsigned int sysfs_nonidx_addr;
+static unsigned int sysfs_idx_addr;
+
+static struct pci_device_id nes_pci_table[] = {
+       {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
+       {0}
+};
+
+MODULE_DEVICE_TABLE(pci, nes_pci_table);
+
+static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *);
+static int nes_net_event(struct notifier_block *, unsigned long, void *);
+static int nes_notifiers_registered;
+
+
+static struct notifier_block nes_inetaddr_notifier = {
+       .notifier_call = nes_inetaddr_event
+};
+
+static struct notifier_block nes_net_notifier = {
+       .notifier_call = nes_net_event
+};
+
+
+
+
+/**
+ * nes_inetaddr_event
+ */
+static int nes_inetaddr_event(struct notifier_block *notifier,
+               unsigned long event, void *ptr)
+{
+       struct in_ifaddr *ifa = ptr;
+       struct net_device *event_netdev = ifa->ifa_dev->dev;
+       struct nes_device *nesdev;
+       struct net_device *netdev;
+       struct nes_vnic *nesvnic;
+       unsigned int addr;
+       unsigned int mask;
+
+       addr = ntohl(ifa->ifa_address);
+       mask = ntohl(ifa->ifa_mask);
+       nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %08X, netmask %08X.\n",
+                       addr, mask);
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
+                               nesdev, nesdev->netdev[0]->name);
+               netdev = nesdev->netdev[0];
+               nesvnic = netdev_priv(netdev);
+               if (netdev == event_netdev) {
+                       if (nesvnic->rdma_enabled == 0) {
+                               nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
+                                               " RDMA is not enabled.\n",
+                                               netdev->name);
+                               return NOTIFY_OK;
+                       }
+                       /* we have ifa->ifa_address/mask here if we need it */
+                       switch (event) {
+                               case NETDEV_DOWN:
+                                       nes_debug(NES_DBG_NETDEV, "event:DOWN\n");
+                                       nes_write_indexed(nesdev,
+                                                       NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), 0);
+
+                                       nes_manage_arp_cache(netdev, netdev->dev_addr,
+                                                       ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);
+                                       nesvnic->local_ipaddr = 0;
+                                       return NOTIFY_OK;
+                                       break;
+                               case NETDEV_UP:
+                                       nes_debug(NES_DBG_NETDEV, "event:UP\n");
+
+                                       if (nesvnic->local_ipaddr != 0) {
+                                               nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");
+                                               return NOTIFY_OK;
+                                       }
+                                       /* Add the address to the IP table */
+                                       nesvnic->local_ipaddr = ifa->ifa_address;
+
+                                       nes_write_indexed(nesdev,
+                                                       NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)),
+                                                       ntohl(ifa->ifa_address));
+                                       nes_manage_arp_cache(netdev, netdev->dev_addr,
+                                                       ntohl(nesvnic->local_ipaddr), NES_ARP_ADD);
+                                       return NOTIFY_OK;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_net_event
+ */
+static int nes_net_event(struct notifier_block *notifier,
+               unsigned long event, void *ptr)
+{
+       struct neighbour *neigh = ptr;
+       struct nes_device *nesdev;
+       struct net_device *netdev;
+       struct nes_vnic *nesvnic;
+
+       switch (event) {
+               case NETEVENT_NEIGH_UPDATE:
+                       list_for_each_entry(nesdev, &nes_dev_list, list) {
+                               /* nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p.\n", nesdev); */
+                               netdev = nesdev->netdev[0];
+                               nesvnic = netdev_priv(netdev);
+                               if (netdev == neigh->dev) {
+                                       if (nesvnic->rdma_enabled == 0) {
+                                               nes_debug(NES_DBG_NETDEV, "Skipping device %s since no RDMA\n",
+                                                               netdev->name);
+                                       } else {
+                                               if (neigh->nud_state & NUD_VALID) {
+                                                       nes_manage_arp_cache(neigh->dev, neigh->ha,
+                                                                       ntohl(*(__be32 *)neigh->primary_key), NES_ARP_ADD);
+                                               } else {
+                                                       nes_manage_arp_cache(neigh->dev, neigh->ha,
+                                                                       ntohl(*(__be32 *)neigh->primary_key), NES_ARP_DELETE);
+                                               }
+                                       }
+                                       return NOTIFY_OK;
+                               }
+                       }
+                       break;
+               default:
+                       nes_debug(NES_DBG_NETDEV, "NETEVENT_ %lu undefined\n", event);
+                       break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_add_ref
+ */
+void nes_add_ref(struct ib_qp *ibqp)
+{
+       struct nes_qp *nesqp;
+
+       nesqp = to_nesqp(ibqp);
+       nes_debug(NES_DBG_QP, "Bumping refcount for QP%u.  Pre-inc value = %u\n",
+                       ibqp->qp_num, atomic_read(&nesqp->refcount));
+       atomic_inc(&nesqp->refcount);
+}
+
+static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
+{
+       unsigned long flags;
+       struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 qp_id;
+
+       atomic_inc(&qps_destroyed);
+
+       /* Free the control structures */
+
+       qp_id = nesqp->hwqp.qp_id;
+       if (nesqp->pbl_vbase) {
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                               nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               nesadapter->free_256pbl++;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+               nesqp->pbl_vbase = NULL;
+
+       } else {
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                               nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+       }
+       nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
+
+       kfree(nesqp->allocated_buffer);
+
+}
+
+/**
+ * nes_rem_ref
+ */
+void nes_rem_ref(struct ib_qp *ibqp)
+{
+       u64 u64temp;
+       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;
+
+       nesqp = to_nesqp(ibqp);
+
+       if (atomic_read(&nesqp->refcount) == 0) {
+               printk(KERN_INFO PFX "%s: Reference count already 0 for QP%d, last aeq = 0x%04X.\n",
+                               __FUNCTION__, ibqp->qp_num, nesqp->last_aeq);
+               BUG();
+       }
+
+       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) {
+                       nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+                       return;
+               }
+               cqp_request->waiting = 0;
+               cqp_request->callback = 1;
+               cqp_request->cqp_callback = nes_cqp_rem_ref_callback;
+               cqp_request->cqp_callback_pointer = nesqp;
+               cqp_wqe = &cqp_request->cqp_wqe;
+
+               nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+               opcode = NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_IWARP;
+
+               if (nesqp->hte_added) {
+                       opcode  |= NES_CQP_QP_DEL_HTE;
+                       nesqp->hte_added = 0;
+               }
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+               u64temp = (u64)nesqp->nesqp_context_pbase;
+               set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+               nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+       }
+}
+
+
+/**
+ * nes_get_qp
+ */
+struct ib_qp *nes_get_qp(struct ib_device *device, int qpn)
+{
+       struct nes_vnic *nesvnic = to_nesvnic(device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+       if ((qpn < NES_FIRST_QPN) || (qpn >= (NES_FIRST_QPN + nesadapter->max_qp)))
+               return NULL;
+
+       return &nesadapter->qp_table[qpn - NES_FIRST_QPN]->ibqp;
+}
+
+
+/**
+ * nes_print_macaddr
+ */
+static void nes_print_macaddr(struct net_device *netdev)
+{
+       nes_debug(NES_DBG_INIT, "%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, IRQ %u\n",
+                       netdev->name,
+                       netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+                       netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
+                       netdev->irq);
+}
+
+
+/**
+ * nes_interrupt - handle interrupts
+ */
+static irqreturn_t nes_interrupt(int irq, void *dev_id)
+{
+       struct nes_device *nesdev = (struct nes_device *)dev_id;
+       int handled = 0;
+       u32 int_mask;
+       u32 int_req;
+       u32 int_stat;
+       u32 intf_int_stat;
+       u32 timer_stat;
+
+       if (nesdev->msi_enabled) {
+               /* No need to read the interrupt pending register if msi is enabled */
+               handled = 1;
+       } else {
+               if (unlikely(nesdev->nesadapter->hw_rev == NE020_REV)) {
+                       /* Master interrupt enable provides synchronization for kicking off bottom half
+                         when interrupt sharing is going on */
+                       int_mask = nes_read32(nesdev->regs + NES_INT_MASK);
+                       if (int_mask & 0x80000000) {
+                               /* Check interrupt status to see if this might be ours */
+                               int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+                               int_req = nesdev->int_req;
+                               if (int_stat&int_req) {
+                                       /* if interesting CEQ or AEQ is pending, claim the interrupt */
+                                       if ((int_stat&int_req) & (~(NES_INT_TIMER|NES_INT_INTF))) {
+                                               handled = 1;
+                                       } else {
+                                               if (((int_stat & int_req) & NES_INT_TIMER) == NES_INT_TIMER) {
+                                                       /* Timer might be running but might be for another function */
+                                                       timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+                                                       if ((timer_stat & nesdev->timer_int_req) != 0) {
+                                                               handled = 1;
+                                                       }
+                                               }
+                                               if ((((int_stat & int_req) & NES_INT_INTF) == NES_INT_INTF) &&
+                                                               (handled == 0)) {
+                                                       intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+                                                       if ((intf_int_stat & nesdev->intf_int_req) != 0) {
+                                                               handled = 1;
+                                                       }
+                                               }
+                                       }
+                                       if (handled) {
+                                               nes_write32(nesdev->regs+NES_INT_MASK, int_mask & (~0x80000000));
+                                               int_mask = nes_read32(nesdev->regs+NES_INT_MASK);
+                                               /* Save off the status to save an additional read */
+                                               nesdev->int_stat = int_stat;
+                                               nesdev->napi_isr_ran = 1;
+                                       }
+                               }
+                       }
+               } else {
+                       handled = nes_read32(nesdev->regs+NES_INT_PENDING);
+               }
+       }
+
+       if (handled) {
+
+               if (nes_napi_isr(nesdev) == 0) {
+                       tasklet_schedule(&nesdev->dpc_tasklet);
+
+               }
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
+}
+
+
+/**
+ * nes_probe - Device initialization
+ */
+static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+       struct net_device *netdev = NULL;
+       struct nes_device *nesdev = NULL;
+       int ret = 0;
+       struct nes_vnic *nesvnic = NULL;
+       void __iomem *mmio_regs = NULL;
+       u8 hw_rev;
+
+       assert(pcidev != NULL);
+       assert(ent != NULL);
+
+       printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n",
+                       DRV_VERSION, pci_name(pcidev));
+
+       ret = pci_enable_device(pcidev);
+       if (ret) {
+               printk(KERN_ERR PFX "Unable to enable PCI device. (%s)\n", pci_name(pcidev));
+               goto bail0;
+       }
+
+       nes_debug(NES_DBG_INIT, "BAR0 (@0x%08lX) size = 0x%lX bytes\n",
+                       (long unsigned int)pci_resource_start(pcidev, BAR_0),
+                       (long unsigned int)pci_resource_len(pcidev, BAR_0));
+       nes_debug(NES_DBG_INIT, "BAR1 (@0x%08lX) size = 0x%lX bytes\n",
+                       (long unsigned int)pci_resource_start(pcidev, BAR_1),
+                       (long unsigned int)pci_resource_len(pcidev, BAR_1));
+
+       /* Make sure PCI base addr are MMIO */
+       if (!(pci_resource_flags(pcidev, BAR_0) & IORESOURCE_MEM) ||
+                       !(pci_resource_flags(pcidev, BAR_1) & IORESOURCE_MEM)) {
+               printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
+               ret = -ENODEV;
+               goto bail1;
+       }
+
+       /* Reserve PCI I/O and memory resources */
+       ret = pci_request_regions(pcidev, DRV_NAME);
+       if (ret) {
+               printk(KERN_ERR PFX "Unable to request regions. (%s)\n", pci_name(pcidev));
+               goto bail1;
+       }
+
+       if ((sizeof(dma_addr_t) > 4)) {
+               ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK);
+               if (ret < 0) {
+                       printk(KERN_ERR PFX "64b DMA mask configuration failed\n");
+                       goto bail2;
+               }
+               ret = pci_set_consistent_dma_mask(pcidev, DMA_64BIT_MASK);
+               if (ret) {
+                       printk(KERN_ERR PFX "64b DMA consistent mask configuration failed\n");
+                       goto bail2;
+               }
+       } else {
+               ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
+               if (ret < 0) {
+                       printk(KERN_ERR PFX "32b DMA mask configuration failed\n");
+                       goto bail2;
+               }
+               ret = pci_set_consistent_dma_mask(pcidev, DMA_32BIT_MASK);
+               if (ret) {
+                       printk(KERN_ERR PFX "32b DMA consistent mask configuration failed\n");
+                       goto bail2;
+               }
+       }
+
+       pci_set_master(pcidev);
+
+       /* Allocate hardware structure */
+       nesdev = kzalloc(sizeof(struct nes_device), GFP_KERNEL);
+       if (!nesdev) {
+               printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", pci_name(pcidev));
+               ret = -ENOMEM;
+               goto bail2;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocated nes device at %p\n", nesdev);
+       nesdev->pcidev = pcidev;
+       pci_set_drvdata(pcidev, nesdev);
+
+       pci_read_config_byte(pcidev, 0x0008, &hw_rev);
+       nes_debug(NES_DBG_INIT, "hw_rev=%u\n", hw_rev);
+
+       spin_lock_init(&nesdev->indexed_regs_lock);
+
+       /* Remap the PCI registers in adapter BAR0 to kernel VA space */
+       mmio_regs = ioremap_nocache(pci_resource_start(pcidev, BAR_0), sizeof(mmio_regs));
+       if (mmio_regs == NULL) {
+               printk(KERN_ERR PFX "Unable to remap BAR0\n");
+               ret = -EIO;
+               goto bail3;
+       }
+       nesdev->regs = mmio_regs;
+       nesdev->index_reg = 0x50 + (PCI_FUNC(pcidev->devfn)*8) + mmio_regs;
+
+       /* Ensure interrupts are disabled */
+       nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+       if (nes_drv_opt & NES_DRV_OPT_ENABLE_MSI) {
+               if (!pci_enable_msi(nesdev->pcidev)) {
+                       nesdev->msi_enabled = 1;
+                       nes_debug(NES_DBG_INIT, "MSI is enabled for device %s\n",
+                                       pci_name(pcidev));
+               } else {
+                       nes_debug(NES_DBG_INIT, "MSI is disabled by linux for device %s\n",
+                                       pci_name(pcidev));
+               }
+       } else {
+               nes_debug(NES_DBG_INIT, "MSI not requested due to driver options for device %s\n",
+                               pci_name(pcidev));
+       }
+
+       nesdev->csr_start = pci_resource_start(nesdev->pcidev, BAR_0);
+       nesdev->doorbell_region = pci_resource_start(nesdev->pcidev, BAR_1);
+
+       /* Init the adapter */
+       nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
+       nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+       if (!nesdev->nesadapter) {
+               printk(KERN_ERR PFX "Unable to initialize adapter.\n");
+               ret = -ENOMEM;
+               goto bail5;
+       }
+
+       /* nesdev->base_doorbell_index =
+                       nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
+       nesdev->base_doorbell_index = 1;
+       nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
+       nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count;
+
+       tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
+
+       /* bring up the Control QP */
+       if (nes_init_cqp(nesdev)) {
+               ret = -ENODEV;
+               goto bail6;
+       }
+
+       /* Arm the CCQ */
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+                       PCI_FUNC(nesdev->pcidev->devfn));
+       nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+       /* Enable the interrupts */
+       nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
+                       (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+       if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
+               nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24));
+       }
+
+       /* TODO: This really should be the first driver to load, not function 0 */
+       if (PCI_FUNC(nesdev->pcidev->devfn) == 0) {
+               /* pick up PCI and critical errors if the first driver to load */
+               nesdev->intf_int_req = NES_INTF_INT_PCIERR | NES_INTF_INT_CRITERR;
+               nesdev->int_req |= NES_INT_INTF;
+       } else {
+               nesdev->intf_int_req = 0;
+       }
+       nesdev->intf_int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0, 0);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 0);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS2, 0x00001265);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS4, 0x18021804);
+
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS3, 0x17801790);
+
+       /* deal with both periodic and one_shot */
+       nesdev->timer_int_req = 0x101 << PCI_FUNC(nesdev->pcidev->devfn);
+       nesdev->nesadapter->timer_int_req |= nesdev->timer_int_req;
+       nes_debug(NES_DBG_INIT, "setting int_req for function %u, nesdev = 0x%04X, adapter = 0x%04X\n",
+                       PCI_FUNC(nesdev->pcidev->devfn),
+                       nesdev->timer_int_req, nesdev->nesadapter->timer_int_req);
+
+       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+
+       list_add_tail(&nesdev->list, &nes_dev_list);
+
+       /* Request an interrupt line for the driver */
+       ret = request_irq(pcidev->irq, nes_interrupt, IRQF_SHARED, DRV_NAME, nesdev);
+       if (ret) {
+               printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
+                               pci_name(pcidev), pcidev->irq);
+               goto bail65;
+       }
+
+       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+
+       if (nes_notifiers_registered == 0) {
+               register_inetaddr_notifier(&nes_inetaddr_notifier);
+               register_netevent_notifier(&nes_net_notifier);
+       }
+       nes_notifiers_registered++;
+
+       /* Initialize network devices */
+               if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) {
+                       goto bail7;
+               }
+
+               /* Register network device */
+               ret = register_netdev(netdev);
+               if (ret) {
+                       printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
+                       nes_netdev_destroy(netdev);
+                       goto bail7;
+               }
+
+               nes_print_macaddr(netdev);
+               /* create a CM core for this netdev */
+               nesvnic = netdev_priv(netdev);
+
+               nesdev->netdev_count++;
+               nesdev->nesadapter->netdev_count++;
+
+
+       printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n",
+                       pci_name(pcidev));
+       return 0;
+
+       bail7:
+       printk(KERN_ERR PFX "bail7\n");
+       while (nesdev->netdev_count > 0) {
+               nesdev->netdev_count--;
+               nesdev->nesadapter->netdev_count--;
+
+               unregister_netdev(nesdev->netdev[nesdev->netdev_count]);
+               nes_netdev_destroy(nesdev->netdev[nesdev->netdev_count]);
+       }
+
+       nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
+                       nesdev->netdev_count, nesdev->nesadapter->netdev_count);
+
+       nes_notifiers_registered--;
+       if (nes_notifiers_registered == 0) {
+               unregister_netevent_notifier(&nes_net_notifier);
+               unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+       }
+
+       list_del(&nesdev->list);
+       nes_destroy_cqp(nesdev);
+
+       bail65:
+       printk(KERN_ERR PFX "bail65\n");
+       free_irq(pcidev->irq, nesdev);
+       if (nesdev->msi_enabled) {
+               pci_disable_msi(pcidev);
+       }
+       bail6:
+       printk(KERN_ERR PFX "bail6\n");
+       tasklet_kill(&nesdev->dpc_tasklet);
+       /* Deallocate the Adapter Structure */
+       nes_destroy_adapter(nesdev->nesadapter);
+
+       bail5:
+       printk(KERN_ERR PFX "bail5\n");
+       iounmap(nesdev->regs);
+
+       bail3:
+       printk(KERN_ERR PFX "bail3\n");
+       kfree(nesdev);
+
+       bail2:
+       pci_release_regions(pcidev);
+
+       bail1:
+       pci_disable_device(pcidev);
+
+       bail0:
+       return ret;
+}
+
+
+/**
+ * nes_remove - unload from kernel
+ */
+static void __devexit nes_remove(struct pci_dev *pcidev)
+{
+       struct nes_device *nesdev = pci_get_drvdata(pcidev);
+       struct net_device *netdev;
+       int netdev_index = 0;
+
+               if (nesdev->netdev_count) {
+                       netdev = nesdev->netdev[netdev_index];
+                       if (netdev) {
+                               netif_stop_queue(netdev);
+                               unregister_netdev(netdev);
+                               nes_netdev_destroy(netdev);
+
+                               nesdev->netdev[netdev_index] = NULL;
+                               nesdev->netdev_count--;
+                               nesdev->nesadapter->netdev_count--;
+                       }
+               }
+
+       nes_notifiers_registered--;
+       if (nes_notifiers_registered == 0) {
+               unregister_netevent_notifier(&nes_net_notifier);
+               unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+       }
+
+       list_del(&nesdev->list);
+       nes_destroy_cqp(nesdev);
+       tasklet_kill(&nesdev->dpc_tasklet);
+
+       /* Deallocate the Adapter Structure */
+       nes_destroy_adapter(nesdev->nesadapter);
+
+       free_irq(pcidev->irq, nesdev);
+
+       if (nesdev->msi_enabled) {
+               pci_disable_msi(pcidev);
+       }
+
+       iounmap(nesdev->regs);
+       kfree(nesdev);
+
+       /* nes_debug(NES_DBG_SHUTDOWN, "calling pci_release_regions.\n"); */
+       pci_release_regions(pcidev);
+       pci_disable_device(pcidev);
+       pci_set_drvdata(pcidev, NULL);
+}
+
+
+static struct pci_driver nes_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = nes_pci_table,
+       .probe = nes_probe,
+       .remove = __devexit_p(nes_remove),
+};
+
+static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
+{
+       unsigned int  devfn = 0xffffffff;
+       unsigned char bus_number = 0xff;
+       unsigned int  i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       devfn      = nesdev->nesadapter->devfn;
+                       bus_number = nesdev->nesadapter->bus_number;
+                       break;
+               }
+               i++;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn);
+}
+
+static ssize_t nes_store_adapter(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       ee_flsh_adapter = simple_strtoul(p, &p, 10);
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_cmd(struct device_driver *ddp, char *buf)
+{
+       u32 eeprom_cmd = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       eeprom_cmd = nes_read32(nesdev->regs + NES_EEPROM_COMMAND);
+                       break;
+               }
+               i++;
+       }
+       return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_cmd);
+}
+
+static ssize_t nes_store_ee_cmd(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_EEPROM_COMMAND, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_data(struct device_driver *ddp, char *buf)
+{
+       u32 eeprom_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       eeprom_data = nes_read32(nesdev->regs + NES_EEPROM_DATA);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_data);
+}
+
+static ssize_t nes_store_ee_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_EEPROM_DATA, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_cmd(struct device_driver *ddp, char *buf)
+{
+       u32 flash_cmd = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       flash_cmd = nes_read32(nesdev->regs + NES_FLASH_COMMAND);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", flash_cmd);
+}
+
+static ssize_t nes_store_flash_cmd(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_FLASH_COMMAND, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_data(struct device_driver *ddp, char *buf)
+{
+       u32 flash_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       flash_data = nes_read32(nesdev->regs + NES_FLASH_DATA);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", flash_data);
+}
+
+static ssize_t nes_store_flash_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_FLASH_DATA, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_addr(struct device_driver *ddp, char *buf)
+{
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_nonidx_addr);
+}
+
+static ssize_t nes_store_nonidx_addr(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+               sysfs_nonidx_addr = simple_strtoul(p, &p, 16);
+
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_data(struct device_driver *ddp, char *buf)
+{
+       u32 nonidx_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       nonidx_data = nes_read32(nesdev->regs + sysfs_nonidx_addr);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", nonidx_data);
+}
+
+static ssize_t nes_store_nonidx_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + sysfs_nonidx_addr, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_addr(struct device_driver *ddp, char *buf)
+{
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_idx_addr);
+}
+
+static ssize_t nes_store_idx_addr(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+               sysfs_idx_addr = simple_strtoul(p, &p, 16);
+
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_data(struct device_driver *ddp, char *buf)
+{
+       u32 idx_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       idx_data = nes_read_indexed(nesdev, sysfs_idx_addr);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", idx_data);
+}
+
+static ssize_t nes_store_idx_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write_indexed(nesdev, sysfs_idx_addr, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
+                  nes_show_adapter, nes_store_adapter);
+static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
+                  nes_show_ee_cmd, nes_store_ee_cmd);
+static DRIVER_ATTR(eeprom_data, S_IRUSR | S_IWUSR,
+                  nes_show_ee_data, nes_store_ee_data);
+static DRIVER_ATTR(flash_cmd, S_IRUSR | S_IWUSR,
+                  nes_show_flash_cmd, nes_store_flash_cmd);
+static DRIVER_ATTR(flash_data, S_IRUSR | S_IWUSR,
+                  nes_show_flash_data, nes_store_flash_data);
+static DRIVER_ATTR(nonidx_addr, S_IRUSR | S_IWUSR,
+                  nes_show_nonidx_addr, nes_store_nonidx_addr);
+static DRIVER_ATTR(nonidx_data, S_IRUSR | S_IWUSR,
+                  nes_show_nonidx_data, nes_store_nonidx_data);
+static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
+                  nes_show_idx_addr, nes_store_idx_addr);
+static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
+                  nes_show_idx_data, nes_store_idx_data);
+
+static int nes_create_driver_sysfs(struct pci_driver *drv)
+{
+       int error;
+       error  = driver_create_file(&drv->driver, &driver_attr_adapter);
+       error |= driver_create_file(&drv->driver, &driver_attr_eeprom_cmd);
+       error |= driver_create_file(&drv->driver, &driver_attr_eeprom_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_flash_cmd);
+       error |= driver_create_file(&drv->driver, &driver_attr_flash_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_nonidx_addr);
+       error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
+       error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
+       return error;
+}
+
+static void nes_remove_driver_sysfs(struct pci_driver *drv)
+{
+       driver_remove_file(&drv->driver, &driver_attr_adapter);
+       driver_remove_file(&drv->driver, &driver_attr_eeprom_cmd);
+       driver_remove_file(&drv->driver, &driver_attr_eeprom_data);
+       driver_remove_file(&drv->driver, &driver_attr_flash_cmd);
+       driver_remove_file(&drv->driver, &driver_attr_flash_data);
+       driver_remove_file(&drv->driver, &driver_attr_nonidx_addr);
+       driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
+       driver_remove_file(&drv->driver, &driver_attr_idx_addr);
+       driver_remove_file(&drv->driver, &driver_attr_idx_data);
+}
+
+/**
+ * nes_init_module - module initialization entry point
+ */
+static int __init nes_init_module(void)
+{
+       int retval;
+       int retval1;
+
+       retval = nes_cm_start();
+       if (retval) {
+               printk(KERN_ERR PFX "Unable to start NetEffect iWARP CM.\n");
+               return retval;
+       }
+       retval = pci_register_driver(&nes_pci_driver);
+       if (retval >= 0) {
+               retval1 = nes_create_driver_sysfs(&nes_pci_driver);
+               if (retval1 < 0)
+                       printk(KERN_ERR PFX "Unable to create NetEffect sys files.\n");
+       }
+       return retval;
+}
+
+
+/**
+ * nes_exit_module - module unload entry point
+ */
+static void __exit nes_exit_module(void)
+{
+       nes_cm_stop();
+       nes_remove_driver_sysfs(&nes_pci_driver);
+
+       pci_unregister_driver(&nes_pci_driver);
+}
+
+
+module_init(nes_init_module);
+module_exit(nes_exit_module);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
new file mode 100644 (file)
index 0000000..fd57e8a
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NES_H
+#define __NES_H
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/crc32c.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/rdma_cm.h>
+#include <rdma/iw_cm.h>
+
+#define NES_SEND_FIRST_WRITE
+
+#define QUEUE_DISCONNECTS
+
+#define DRV_BUILD   "1"
+
+#define DRV_NAME    "iw_nes"
+#define DRV_VERSION "1.0 KO Build " DRV_BUILD
+#define PFX         DRV_NAME ": "
+
+/*
+ * NetEffect PCI vendor id and NE010 PCI device id.
+ */
+#ifndef PCI_VENDOR_ID_NETEFFECT        /* not in pci.ids yet */
+#define PCI_VENDOR_ID_NETEFFECT       0x1678
+#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
+#endif
+
+#define NE020_REV   4
+#define NE020_REV1  5
+
+#define BAR_0       0
+#define BAR_1       2
+
+#define RX_BUF_SIZE             (1536 + 8)
+#define NES_REG0_SIZE           (4 * 1024)
+#define NES_TX_TIMEOUT          (6*HZ)
+#define NES_FIRST_QPN           64
+#define NES_SW_CONTEXT_ALIGN    1024
+
+#define NES_NIC_MAX_NICS        16
+#define NES_MAX_ARP_TABLE_SIZE  4096
+
+#define NES_NIC_CEQ_SIZE        8
+/* NICs will be on a separate CQ */
+#define NES_CCEQ_SIZE ((nesadapter->max_cq / nesadapter->port_count) - 32)
+
+#define NES_MAX_PORT_COUNT 4
+
+#define MAX_DPC_ITERATIONS               128
+
+#define NES_CQP_REQUEST_NO_DOORBELL_RING 0
+#define NES_CQP_REQUEST_RING_DOORBELL    1
+
+#define NES_DRV_OPT_ENABLE_MPA_VER_0     0x00000001
+#define NES_DRV_OPT_DISABLE_MPA_CRC      0x00000002
+#define NES_DRV_OPT_DISABLE_FIRST_WRITE  0x00000004
+#define NES_DRV_OPT_DISABLE_INTF         0x00000008
+#define NES_DRV_OPT_ENABLE_MSI           0x00000010
+#define NES_DRV_OPT_DUAL_LOGICAL_PORT    0x00000020
+#define NES_DRV_OPT_SUPRESS_OPTION_BC    0x00000040
+#define NES_DRV_OPT_NO_INLINE_DATA       0x00000080
+#define NES_DRV_OPT_DISABLE_INT_MOD      0x00000100
+#define NES_DRV_OPT_DISABLE_VIRT_WQ      0x00000200
+
+#define NES_AEQ_EVENT_TIMEOUT         2500
+#define NES_DISCONNECT_EVENT_TIMEOUT  2000
+
+/* debug levels */
+/* must match userspace */
+#define NES_DBG_HW          0x00000001
+#define NES_DBG_INIT        0x00000002
+#define NES_DBG_ISR         0x00000004
+#define NES_DBG_PHY         0x00000008
+#define NES_DBG_NETDEV      0x00000010
+#define NES_DBG_CM          0x00000020
+#define NES_DBG_CM1         0x00000040
+#define NES_DBG_NIC_RX      0x00000080
+#define NES_DBG_NIC_TX      0x00000100
+#define NES_DBG_CQP         0x00000200
+#define NES_DBG_MMAP        0x00000400
+#define NES_DBG_MR          0x00000800
+#define NES_DBG_PD          0x00001000
+#define NES_DBG_CQ          0x00002000
+#define NES_DBG_QP          0x00004000
+#define NES_DBG_MOD_QP      0x00008000
+#define NES_DBG_AEQ         0x00010000
+#define NES_DBG_IW_RX       0x00020000
+#define NES_DBG_IW_TX       0x00040000
+#define NES_DBG_SHUTDOWN    0x00080000
+#define NES_DBG_RSVD1       0x10000000
+#define NES_DBG_RSVD2       0x20000000
+#define NES_DBG_RSVD3       0x40000000
+#define NES_DBG_RSVD4       0x80000000
+#define NES_DBG_ALL         0xffffffff
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define nes_debug(level, fmt, args...) \
+       if (level & nes_debug_level) \
+               printk(KERN_ERR PFX "%s[%u]: " fmt, __FUNCTION__, __LINE__, ##args)
+
+#define assert(expr)                                                \
+if (!(expr)) {                                                       \
+       printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n",  \
+                  #expr, __FILE__, __FUNCTION__, __LINE__);                \
+}
+
+#define NES_EVENT_TIMEOUT   1200000
+#else
+#define nes_debug(level, fmt, args...)
+#define assert(expr)          do {} while (0)
+
+#define NES_EVENT_TIMEOUT   100000
+#endif
+
+#include "nes_hw.h"
+#include "nes_verbs.h"
+#include "nes_context.h"
+#include "nes_user.h"
+#include "nes_cm.h"
+
+extern int max_mtu;
+extern int nics_per_function;
+#define max_frame_len (max_mtu+ETH_HLEN)
+extern int interrupt_mod_interval;
+extern int nes_if_count;
+extern int mpa_version;
+extern int disable_mpa_crc;
+extern unsigned int send_first;
+extern unsigned int nes_drv_opt;
+extern unsigned int nes_debug_level;
+
+extern struct list_head nes_adapter_list;
+extern struct list_head nes_dev_list;
+
+extern struct nes_cm_core *g_cm_core;
+
+extern atomic_t cm_connects;
+extern atomic_t cm_accepts;
+extern atomic_t cm_disconnects;
+extern atomic_t cm_closes;
+extern atomic_t cm_connecteds;
+extern atomic_t cm_connect_reqs;
+extern atomic_t cm_rejects;
+extern atomic_t mod_qp_timouts;
+extern atomic_t qps_created;
+extern atomic_t qps_destroyed;
+extern atomic_t sw_qps_destroyed;
+extern u32 mh_detected;
+extern u32 mh_pauses_sent;
+extern u32 cm_packets_sent;
+extern u32 cm_packets_bounced;
+extern u32 cm_packets_created;
+extern u32 cm_packets_received;
+extern u32 cm_packets_dropped;
+extern u32 cm_packets_retrans;
+extern u32 cm_listens_created;
+extern u32 cm_listens_destroyed;
+extern u32 cm_backlog_drops;
+extern atomic_t cm_loopbacks;
+extern atomic_t cm_nodes_created;
+extern atomic_t cm_nodes_destroyed;
+extern atomic_t cm_accel_dropped_pkts;
+extern atomic_t cm_resets_recvd;
+
+extern u32 crit_err_count;
+extern u32 int_mod_timer_init;
+extern u32 int_mod_cq_depth_256;
+extern u32 int_mod_cq_depth_128;
+extern u32 int_mod_cq_depth_32;
+extern u32 int_mod_cq_depth_24;
+extern u32 int_mod_cq_depth_16;
+extern u32 int_mod_cq_depth_4;
+extern u32 int_mod_cq_depth_1;
+
+extern atomic_t cqp_reqs_allocated;
+extern atomic_t cqp_reqs_freed;
+extern atomic_t cqp_reqs_dynallocated;
+extern atomic_t cqp_reqs_dynfreed;
+extern atomic_t cqp_reqs_queued;
+extern atomic_t cqp_reqs_redriven;
+
+
+struct nes_device {
+       struct nes_adapter         *nesadapter;
+       void __iomem           *regs;
+       void __iomem           *index_reg;
+       struct pci_dev         *pcidev;
+       struct net_device      *netdev[NES_NIC_MAX_NICS];
+       u64                    link_status_interrupts;
+       struct tasklet_struct  dpc_tasklet;
+       spinlock_t             indexed_regs_lock;
+       unsigned long          csr_start;
+       unsigned long          doorbell_region;
+       unsigned long          doorbell_start;
+       unsigned long          mac_tx_errors;
+       unsigned long          mac_pause_frames_sent;
+       unsigned long          mac_pause_frames_received;
+       unsigned long          mac_rx_errors;
+       unsigned long          mac_rx_crc_errors;
+       unsigned long          mac_rx_symbol_err_frames;
+       unsigned long          mac_rx_jabber_frames;
+       unsigned long          mac_rx_oversized_frames;
+       unsigned long          mac_rx_short_frames;
+       unsigned long          port_rx_discards;
+       unsigned long          port_tx_discards;
+       unsigned int           mac_index;
+       unsigned int           nes_stack_start;
+
+       /* Control Structures */
+       void                   *cqp_vbase;
+       dma_addr_t             cqp_pbase;
+       u32                    cqp_mem_size;
+       u8                     ceq_index;
+       u8                     nic_ceq_index;
+       struct nes_hw_cqp      cqp;
+       struct nes_hw_cq       ccq;
+       struct list_head       cqp_avail_reqs;
+       struct list_head       cqp_pending_reqs;
+       struct nes_cqp_request *nes_cqp_requests;
+
+       u32                    int_req;
+       u32                    int_stat;
+       u32                    timer_int_req;
+       u32                    timer_only_int_count;
+       u32                    intf_int_req;
+       u32                    last_mac_tx_pauses;
+       u32                    last_used_chunks_tx;
+       struct list_head       list;
+
+       u16                    base_doorbell_index;
+       u16                    currcq_count;
+       u16                    deepcq_count;
+       u8                     msi_enabled;
+       u8                     netdev_count;
+       u8                     napi_isr_ran;
+       u8                     disable_rx_flow_control;
+       u8                     disable_tx_flow_control;
+};
+
+
+static inline void
+set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
+{
+       wqe_words[index]     = cpu_to_le32((u32) ((unsigned long)value));
+       wqe_words[index + 1] = cpu_to_le32((u32)(upper_32_bits((unsigned long)value)));
+}
+
+static inline void
+set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value)
+{
+       wqe_words[index] = cpu_to_le32(value);
+}
+
+static inline void
+nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev)
+{
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_CTX_LOW_IDX,
+                       (u64)((unsigned long) &nesdev->cqp));
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]   = 0;
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]  = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX]       = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX]       = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX]        = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX]       = 0;
+}
+
+static inline void
+nes_fill_init_qp_wqe(struct nes_hw_qp_wqe *wqe, struct nes_qp *nesqp, u32 head)
+{
+       u32 value;
+       value = ((u32)((unsigned long) nesqp)) | head;
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX,
+                       (u32)(upper_32_bits((unsigned long)(nesqp))));
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, value);
+}
+
+/* Read from memory-mapped device */
+static inline u32 nes_read_indexed(struct nes_device *nesdev, u32 reg_index)
+{
+       unsigned long flags;
+       void __iomem *addr = nesdev->index_reg;
+       u32 value;
+
+       spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+       writel(reg_index, addr);
+       value = readl((void __iomem *)addr + 4);
+
+       spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+       return value;
+}
+
+static inline u32 nes_read32(const void __iomem *addr)
+{
+       return readl(addr);
+}
+
+static inline u16 nes_read16(const void __iomem *addr)
+{
+       return readw(addr);
+}
+
+static inline u8 nes_read8(const void __iomem *addr)
+{
+       return readb(addr);
+}
+
+/* Write to memory-mapped device */
+static inline void nes_write_indexed(struct nes_device *nesdev, u32 reg_index, u32 val)
+{
+       unsigned long flags;
+       void __iomem *addr = nesdev->index_reg;
+
+       spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+       writel(reg_index, addr);
+       writel(val, (void __iomem *)addr + 4);
+
+       spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+}
+
+static inline void nes_write32(void __iomem *addr, u32 val)
+{
+       writel(val, addr);
+}
+
+static inline void nes_write16(void __iomem *addr, u16 val)
+{
+       writew(val, addr);
+}
+
+static inline void nes_write8(void __iomem *addr, u8 val)
+{
+       writeb(val, addr);
+}
+
+
+
+static inline int nes_alloc_resource(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 max_resources,
+               u32 *req_resource_num, u32 *next)
+{
+       unsigned long flags;
+       u32 resource_num;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+       resource_num = find_next_zero_bit(resource_array, max_resources, *next);
+       if (resource_num >= max_resources) {
+               resource_num = find_first_zero_bit(resource_array, max_resources);
+               if (resource_num >= max_resources) {
+                       printk(KERN_ERR PFX "%s: No available resourcess.\n", __FUNCTION__);
+                       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+                       return -EMFILE;
+               }
+       }
+       set_bit(resource_num, resource_array);
+       *next = resource_num+1;
+       if (*next == max_resources) {
+               *next = 0;
+       }
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+       *req_resource_num = resource_num;
+
+       return 0;
+}
+
+static inline int nes_is_resource_allocated(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 resource_num)
+{
+       unsigned long flags;
+       int bit_is_set;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+       bit_is_set = test_bit(resource_num, resource_array);
+       nes_debug(NES_DBG_HW, "resource_num %u is%s allocated.\n",
+                       resource_num, (bit_is_set ? "": " not"));
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+
+       return bit_is_set;
+}
+
+static inline void nes_free_resource(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 resource_num)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+       clear_bit(resource_num, resource_array);
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+}
+
+static inline struct nes_vnic *to_nesvnic(struct ib_device *ibdev)
+{
+       return container_of(ibdev, struct nes_ib_device, ibdev)->nesvnic;
+}
+
+static inline struct nes_pd *to_nespd(struct ib_pd *ibpd)
+{
+       return container_of(ibpd, struct nes_pd, ibpd);
+}
+
+static inline struct nes_ucontext *to_nesucontext(struct ib_ucontext *ibucontext)
+{
+       return container_of(ibucontext, struct nes_ucontext, ibucontext);
+}
+
+static inline struct nes_mr *to_nesmr(struct ib_mr *ibmr)
+{
+       return container_of(ibmr, struct nes_mr, ibmr);
+}
+
+static inline struct nes_mr *to_nesmr_from_ibfmr(struct ib_fmr *ibfmr)
+{
+       return container_of(ibfmr, struct nes_mr, ibfmr);
+}
+
+static inline struct nes_mr *to_nesmw(struct ib_mw *ibmw)
+{
+       return container_of(ibmw, struct nes_mr, ibmw);
+}
+
+static inline struct nes_fmr *to_nesfmr(struct nes_mr *nesmr)
+{
+       return container_of(nesmr, struct nes_fmr, nesmr);
+}
+
+static inline struct nes_cq *to_nescq(struct ib_cq *ibcq)
+{
+       return container_of(ibcq, struct nes_cq, ibcq);
+}
+
+static inline struct nes_qp *to_nesqp(struct ib_qp *ibqp)
+{
+       return container_of(ibqp, struct nes_qp, ibqp);
+}
+
+
+
+/* nes.c */
+void nes_add_ref(struct ib_qp *);
+void nes_rem_ref(struct ib_qp *);
+struct ib_qp *nes_get_qp(struct ib_device *, int);
+
+
+/* nes_hw.c */
+struct nes_adapter *nes_init_adapter(struct nes_device *, u8);
+void  nes_nic_init_timer_defaults(struct nes_device *, u8);
+unsigned int nes_reset_adapter_ne020(struct nes_device *, u8 *);
+int nes_init_serdes(struct nes_device *, u8, u8, u8);
+void nes_init_csr_ne020(struct nes_device *, u8, u8);
+void nes_destroy_adapter(struct nes_adapter *);
+int nes_init_cqp(struct nes_device *);
+int nes_init_phy(struct nes_device *);
+int nes_init_nic_qp(struct nes_device *, struct net_device *);
+void nes_destroy_nic_qp(struct nes_vnic *);
+int nes_napi_isr(struct nes_device *);
+void nes_dpc(unsigned long);
+void nes_process_ceq(struct nes_device *, struct nes_hw_ceq *);
+void nes_process_aeq(struct nes_device *, struct nes_hw_aeq *);
+void nes_process_mac_intr(struct nes_device *, u32);
+void nes_nic_napi_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_cqp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+void nes_process_iwarp_aeqe(struct nes_device *, struct nes_hw_aeqe *);
+void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+int nes_destroy_cqp(struct nes_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_nic.c */
+void nes_netdev_set_multicast_list(struct net_device *);
+void nes_netdev_exit(struct nes_vnic *);
+struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
+void nes_netdev_destroy(struct net_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_cm.c */
+void *nes_cm_create(struct net_device *);
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+void nes_update_arp(unsigned char *, u32, u32, u16, u16);
+void nes_manage_arp_cache(struct net_device *, unsigned char *, u32, u32);
+void nes_sock_release(struct nes_qp *, unsigned long *);
+struct nes_cm_core *nes_cm_alloc_core(void);
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *, u32, u32);
+int nes_manage_apbvt(struct nes_vnic *, u32, u32, u32);
+int nes_cm_disconn(struct nes_qp *);
+void nes_cm_disconn_worker(void *);
+
+/* nes_verbs.c */
+int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32);
+int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
+struct nes_ib_device *nes_init_ofa_device(struct net_device *);
+void nes_destroy_ofa_device(struct nes_ib_device *);
+int nes_register_ofa_device(struct nes_ib_device *);
+void nes_unregister_ofa_device(struct nes_ib_device *);
+
+/* nes_util.c */
+int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
+void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
+void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
+void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16);
+void nes_read_10G_phy_reg(struct nes_device *, u16, u8);
+struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
+void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int);
+int nes_arp_table(struct nes_device *, u32, u8 *, u32);
+void nes_mh_fix(unsigned long);
+void nes_clc(unsigned long);
+void nes_dump_mem(unsigned int, void *, int);
+u32 nes_crc32(u32, u32, u32, u32, u8 *, u32, u32, u32);
+
+#endif /* __NES_H */
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
new file mode 100644 (file)
index 0000000..bd5cfea
--- /dev/null
@@ -0,0 +1,3088 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+
+#define TCPOPT_TIMESTAMP 8
+
+#include <asm/atomic.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/notifier.h>
+#include <linux/net.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+#include "nes.h"
+
+u32 cm_packets_sent;
+u32 cm_packets_bounced;
+u32 cm_packets_dropped;
+u32 cm_packets_retrans;
+u32 cm_packets_created;
+u32 cm_packets_received;
+u32 cm_listens_created;
+u32 cm_listens_destroyed;
+u32 cm_backlog_drops;
+atomic_t cm_loopbacks;
+atomic_t cm_nodes_created;
+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 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 *);
+static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
+
+
+/* External CM API Interface */
+/* instance of function pointers for client API */
+/* set address of this instance to cm_core->cm_ops at cm_core alloc */
+static struct nes_cm_ops nes_cm_api = {
+       mini_cm_accelerated,
+       mini_cm_listen,
+       mini_cm_del_listen,
+       mini_cm_connect,
+       mini_cm_close,
+       mini_cm_accept,
+       mini_cm_reject,
+       mini_cm_recv_pkt,
+       mini_cm_dealloc_core,
+       mini_cm_get,
+       mini_cm_set
+};
+
+struct nes_cm_core *g_cm_core;
+
+atomic_t cm_connects;
+atomic_t cm_accepts;
+atomic_t cm_disconnects;
+atomic_t cm_closes;
+atomic_t cm_connecteds;
+atomic_t cm_connect_reqs;
+atomic_t cm_rejects;
+
+
+/**
+ * create_event
+ */
+static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
+               enum nes_cm_event_type type)
+{
+       struct nes_cm_event *event;
+
+       if (!cm_node->cm_id)
+               return NULL;
+
+       /* allocate an empty event */
+       event = kzalloc(sizeof(*event), GFP_ATOMIC);
+
+       if (!event)
+               return NULL;
+
+       event->type = type;
+       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;
+
+       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_cm_post_event(event);
+       return event;
+}
+
+
+/**
+ * send_mpa_request
+ */
+int send_mpa_request(struct nes_cm_node *cm_node)
+{
+       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");
+               return -1;
+       }
+
+       /* send an MPA Request frame */
+       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 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)
+{
+       struct ietf_mpa_frame *mpa_frame;
+
+       /* 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;
+       }
+
+       mpa_frame = (struct ietf_mpa_frame *)buffer;
+       cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len);
+
+       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;
+       }
+
+       /* 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);
+
+       return 0;
+}
+
+
+/**
+ * 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.
+ */
+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;
+       struct ethhdr *ethh;
+       u8 *buf;
+       u16 packetsize = sizeof(*iph);
+
+       packetsize += sizeof(*tcph);
+       packetsize +=  optionsize + datasize;
+
+       memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph));
+
+       skb->len = 0;
+       buf = skb_put(skb, packetsize + ETH_HLEN);
+
+       ethh = (struct ethhdr *) buf;
+       buf += ETH_HLEN;
+
+       iph = (struct iphdr *)buf;
+       buf += sizeof(*iph);
+       tcph = (struct tcphdr *)buf;
+       skb_reset_mac_header(skb);
+       skb_set_network_header(skb, ETH_HLEN);
+       skb_set_transport_header(skb, ETH_HLEN+sizeof(*iph));
+       buf += sizeof(*tcph);
+
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       skb->protocol = htons(0x800);
+       skb->data_len = 0;
+       skb->mac_len = ETH_HLEN;
+
+       memcpy(ethh->h_dest, cm_node->rem_mac, ETH_ALEN);
+       memcpy(ethh->h_source, cm_node->loc_mac, ETH_ALEN);
+       ethh->h_proto = htons(0x0800);
+
+       iph->version = IPVERSION;
+       iph->ihl = 5;           /* 5 * 4Byte words, IP headr len */
+       iph->tos = 0;
+       iph->tot_len = htons(packetsize);
+       iph->id = htons(++cm_node->tcp_cntxt.loc_id);
+
+       iph->frag_off = htons(0x4000);
+       iph->ttl = 0x40;
+       iph->protocol = 0x06;   /* IPPROTO_TCP */
+
+       iph->saddr = htonl(cm_node->loc_addr);
+       iph->daddr = htonl(cm_node->rem_addr);
+
+       tcph->source = htons(cm_node->loc_port);
+       tcph->dest = htons(cm_node->rem_port);
+       tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
+
+       if (flags & SET_ACK) {
+               cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
+               tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
+               tcph->ack = 1;
+       } else
+               tcph->ack_seq = 0;
+
+       if (flags & SET_SYN) {
+               cm_node->tcp_cntxt.loc_seq_num++;
+               tcph->syn = 1;
+       } else
+               cm_node->tcp_cntxt.loc_seq_num += datasize;     /* data (no headers) */
+
+       if (flags & SET_FIN)
+               tcph->fin = 1;
+
+       if (flags & SET_RST)
+               tcph->rst = 1;
+
+       tcph->doff = (u16)((sizeof(*tcph) + optionsize + 3) >> 2);
+       tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
+       tcph->urg_ptr = 0;
+       if (optionsize)
+               memcpy(buf, options, optionsize);
+       buf += optionsize;
+       if (datasize)
+               memcpy(buf, data, datasize);
+
+       skb_shinfo(skb)->nr_frags = 0;
+       cm_packets_created++;
+
+       return skb;
+}
+
+
+/**
+ * print_core - dump a cm core
+ */
+static void print_core(struct nes_cm_core *core)
+{
+       nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+       nes_debug(NES_DBG_CM, "CM Core  -- (core = %p )\n", core);
+       if (!core)
+               return;
+       nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+       nes_debug(NES_DBG_CM, "Session ID    : %u \n", atomic_read(&core->session_id));
+
+       nes_debug(NES_DBG_CM, "State         : %u \n",  core->state);
+
+       nes_debug(NES_DBG_CM, "Tx Free cnt   : %u \n", skb_queue_len(&core->tx_free_list));
+       nes_debug(NES_DBG_CM, "Listen Nodes  : %u \n", atomic_read(&core->listen_node_cnt));
+       nes_debug(NES_DBG_CM, "Active Nodes  : %u \n", atomic_read(&core->node_cnt));
+
+       nes_debug(NES_DBG_CM, "core          : %p \n", core);
+
+       nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");
+}
+
+
+/**
+ * schedule_nes_timer
+ * note - cm_node needs to be protected before calling this. Encase in:
+ *                     rem_ref_cm_node(cm_core, cm_node);add_ref_cm_node(cm_node);
+ */
+int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
+               enum nes_timer_type type, int send_retrans,
+               int close_when_complete)
+{
+       unsigned long  flags;
+       struct nes_cm_core *cm_core;
+       struct nes_timer_entry *new_send;
+       int ret = 0;
+       u32 was_timer_set;
+
+       new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
+       if (!new_send)
+               return -1;
+       if (!cm_node)
+               return -EINVAL;
+
+       /* new_send->timetosend = currenttime */
+       new_send->retrycount = NES_DEFAULT_RETRYS;
+       new_send->retranscount = NES_DEFAULT_RETRANS;
+       new_send->skb = skb;
+       new_send->timetosend = jiffies;
+       new_send->type = type;
+       new_send->netdev = cm_node->netdev;
+       new_send->send_retrans = send_retrans;
+       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 */
+               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 (type == NES_TIMER_TYPE_SEND) {
+               new_send->seq_num = htonl(tcp_hdr(skb)->seq);
+               atomic_inc(&new_send->skb->users);
+
+               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);
+                       atomic_dec(&new_send->skb->users);
+                       new_send->timetosend = jiffies;
+               } else {
+                       cm_packets_sent++;
+                       if (!send_retrans) {
+                               if (close_when_complete)
+                                       rem_ref_cm_node(cm_node->cm_core, cm_node);
+                               dev_kfree_skb_any(new_send->skb);
+                               kfree(new_send);
+                               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 = htonl(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);
+
+       if (!was_timer_set) {
+               cm_core->tcp_timer.expires = new_send->timetosend;
+               add_timer(&cm_core->tcp_timer);
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_timer_tick
+ */
+void nes_cm_timer_tick(unsigned long pass)
+{
+       unsigned long flags, qplockflags;
+       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 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;
+
+       spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+       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) {
+                                       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);
+                       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);
+                       }
+                       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);
+                       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;
+                                               settimer = 1;
+                                       }
+                                       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);
+                                       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);
+                               continue;
+                       }
+
+                       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 */
+                                       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);
+                               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);
+                       ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
+                       if (ret != NETDEV_TX_OK) {
+                               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);
+                       if (send_entry->send_retrans) {
+                               send_entry->retranscount--;
+                               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;
+                       }
+               }
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+               rem_ref_cm_node(cm_core, cm_node);
+
+               spin_lock_irqsave(&cm_core->ht_lock, flags);
+               if (ret != NETDEV_TX_OK)
+                       break;
+       }
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       if (settimer) {
+               if (!timer_pending(&cm_core->tcp_timer)) {
+                       cm_core->tcp_timer.expires  = nexttimeout;
+                       add_timer(&cm_core->tcp_timer);
+               }
+       }
+}
+
+
+/**
+ * send_syn
+ */
+int send_syn(struct nes_cm_node *cm_node, u32 sendack)
+{
+       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];
+
+       int optionssize = 0;
+       /* Sending MSS option */
+       union all_known_options *options;
+
+       if (!cm_node)
+               return -EINVAL;
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_mss.optionnum = OPTION_NUMBER_MSS;
+       options->as_mss.length = sizeof(struct option_mss);
+       options->as_mss.mss = htons(cm_node->tcp_cntxt.mss);
+       optionssize += sizeof(struct option_mss);
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;
+       options->as_windowscale.length = sizeof(struct option_windowscale);
+       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)
+                       ) {
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_base.optionnum = OPTION_NUMBER_WRITE0;
+               options->as_base.length = sizeof(struct option_base);
+               optionssize += sizeof(struct option_base);
+               /* we need the size to be a multiple of 4 */
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_end = 1;
+               optionssize += 1;
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_end = 1;
+               optionssize += 1;
+       }
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_end = OPTION_NUMBER_END;
+       optionssize += 1;
+
+       skb = get_free_pkt(cm_node);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       if (sendack)
+               flags |= SET_ACK;
+
+       form_cm_frame(skb, cm_node, optionsbuffer, optionssize, NULL, 0, flags);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+       return ret;
+}
+
+
+/**
+ * send_reset
+ */
+int send_reset(struct nes_cm_node *cm_node)
+{
+       int ret;
+       struct sk_buff *skb = get_free_pkt(cm_node);
+       int flags = SET_RST | SET_ACK;
+
+       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);
+
+       return ret;
+}
+
+
+/**
+ * send_ack
+ */
+int send_ack(struct nes_cm_node *cm_node)
+{
+       int ret;
+       struct sk_buff *skb = get_free_pkt(cm_node);
+
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 0);
+
+       return ret;
+}
+
+
+/**
+ * send_fin
+ */
+int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+       int ret;
+
+       /* if we didn't get a frame get one */
+       if (!skb)
+               skb = get_free_pkt(cm_node);
+
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK | SET_FIN);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+       return ret;
+}
+
+
+/**
+ * get_free_pkt
+ */
+struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
+{
+       struct sk_buff *skb, *new_skb;
+
+       /* check to see if we need to repopulate the free tx pkt queue */
+       if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
+               while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
+                               cm_node->cm_core->free_tx_pkt_max) {
+                       /* replace the frame we took, we won't get it back */
+                       new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
+                       BUG_ON(!new_skb);
+                       /* add a replacement frame to the free tx list head */
+                       skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
+               }
+       }
+
+       skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
+
+       return skb;
+}
+
+
+/**
+ * make_hashkey - generate hash key from node tuple
+ */
+static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
+               nes_addr_t rem_addr)
+{
+       u32 hashkey = 0;
+
+       hashkey = loc_addr + rem_addr + loc_port + rem_port;
+       hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
+
+       return hashkey;
+}
+
+
+/**
+ * find_node - find a cm node that matches the reference cm node
+ */
+static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
+               u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
+{
+       unsigned long flags;
+       u32 hashkey;
+       struct list_head *list_pos;
+       struct list_head *hte;
+       struct nes_cm_node *cm_node;
+
+       /* make a hash index key for this packet */
+       hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
+
+       /* get a handle on the hte */
+       hte = &cm_core->connected_nodes;
+
+       nes_debug(NES_DBG_CM, "Searching for an owner node:%x:%x from core %p->%p\n",
+                       loc_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(list_pos, hte) {
+               cm_node = container_of(list_pos, struct nes_cm_node, list);
+               /* compare quad, return node handle if a match */
+               nes_debug(NES_DBG_CM, "finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",
+                               cm_node->loc_addr, cm_node->loc_port,
+                               loc_addr, loc_port,
+                               cm_node->rem_addr, cm_node->rem_port,
+                               rem_addr, rem_port);
+               if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&
+                               (cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {
+                       add_ref_cm_node(cm_node);
+                       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+                       return cm_node;
+               }
+       }
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       /* no owner node */
+       return NULL;
+}
+
+
+/**
+ * find_listener - find a cm node listening on this addr-port pair
+ */
+static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
+               nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)
+{
+       unsigned long flags;
+       struct list_head *listen_list;
+       struct nes_cm_listener *listen_node;
+
+       /* walk list and find cm_node associated with this session ID */
+       spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+       list_for_each(listen_list, &cm_core->listen_list.list) {
+               listen_node = container_of(listen_list, struct nes_cm_listener, list);
+               /* compare node pair, return node handle if a match */
+               if (((listen_node->loc_addr == dst_addr) ||
+                               listen_node->loc_addr == 0x00000000) &&
+                               (listen_node->loc_port == dst_port) &&
+                               (listener_state & listen_node->listener_state)) {
+                       atomic_inc(&listen_node->ref_count);
+                       spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+                       return listen_node;
+               }
+       }
+       spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+       nes_debug(NES_DBG_CM, "Unable to find listener- %x:%x\n",
+                       dst_addr, dst_port);
+
+       /* no listener */
+       return NULL;
+}
+
+
+/**
+ * add_hte_node - add a cm node to the hash table
+ */
+static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+       unsigned long flags;
+       u32 hashkey;
+       struct list_head *hte;
+
+       if (!cm_node || !cm_core)
+               return -EINVAL;
+
+       nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n");
+
+       /* first, make an index into our hash table */
+       hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
+                       cm_node->rem_port, cm_node->rem_addr);
+       cm_node->hashkey = hashkey;
+
+       spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+       /* get a handle on the hash table element (list head for this slot) */
+       hte = &cm_core->connected_nodes;
+       list_add_tail(&cm_node->list, hte);
+       atomic_inc(&cm_core->ht_node_cnt);
+
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       return 0;
+}
+
+
+/**
+ * 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)
+{
+       int ret = 1;
+       unsigned long flags;
+       spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+       if (!atomic_dec_return(&listener->ref_count)) {
+               list_del(&listener->list);
+
+               /* decrement our listen node count */
+               atomic_dec(&cm_core->listen_node_cnt);
+
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+               if (listener->nesvnic) {
+                       nes_manage_apbvt(listener->nesvnic, listener->loc_port,
+                                       PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+               }
+
+               nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
+
+               kfree(listener);
+               ret = 0;
+               cm_listens_destroyed++;
+       } else {
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+       }
+       if (listener) {
+               if (atomic_read(&listener->pend_accepts_cnt) > 0)
+                       nes_debug(NES_DBG_CM, "destroying listener (%p)"
+                                       " with non-zero pending accepts=%u\n",
+                                       listener, atomic_read(&listener->pend_accepts_cnt));
+       }
+
+       return ret;
+}
+
+
+/**
+ * mini_cm_del_listen
+ */
+static int mini_cm_del_listen(struct nes_cm_core *cm_core,
+               struct nes_cm_listener *listener)
+{
+       listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;
+       listener->cm_id = NULL; /* going to be destroyed pretty soon */
+       return mini_cm_dec_refcnt_listen(cm_core, listener, 1);
+}
+
+
+/**
+ * mini_cm_accelerated
+ */
+static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
+               struct nes_cm_node *cm_node)
+{
+       u32 was_timer_set;
+       cm_node->accelerated = 1;
+
+       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);
+       }
+
+       was_timer_set = timer_pending(&cm_core->tcp_timer);
+       if (!was_timer_set) {
+               cm_core->tcp_timer.expires = jiffies + NES_SHORT_TIME;
+               add_timer(&cm_core->tcp_timer);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_addr_send_arp
+ */
+static void nes_addr_send_arp(u32 dst_ip)
+{
+       struct rtable *rt;
+       struct flowi fl;
+
+       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",
+                               __FUNCTION__, dst_ip);
+               return;
+       }
+
+       neigh_event_send(rt->u.dst.neighbour, NULL);
+       ip_rt_put(rt);
+}
+
+
+/**
+ * make_cm_node - create a new instance of a cm node
+ */
+static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
+               struct nes_vnic *nesvnic, struct nes_cm_info *cm_info,
+               struct nes_cm_listener *listener)
+{
+       struct nes_cm_node *cm_node;
+       struct timespec ts;
+       int arpindex = 0;
+       struct nes_device *nesdev;
+       struct nes_adapter *nesadapter;
+
+       /* create an hte and cm_node for this instance */
+       cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
+       if (!cm_node)
+               return NULL;
+
+       /* set our node specific transport info */
+       cm_node->loc_addr = cm_info->loc_addr;
+       cm_node->rem_addr = cm_info->rem_addr;
+       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 = %x:%x, rem = %x:%x\n",
+                       cm_node->loc_addr, cm_node->loc_port, 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);
+
+       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);
+
+       cm_node->loopbackpartner = NULL;
+       atomic_set(&cm_node->ref_count, 1);
+       /* associate our parent CM core */
+       cm_node->cm_core = cm_core;
+       cm_node->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;
+       cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+       cm_node->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>
+                       NES_CM_DEFAULT_RCV_WND_SCALE;
+       ts = current_kernel_time();
+       cm_node->tcp_cntxt.loc_seq_num = htonl(ts.tv_nsec);
+       cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -
+                       sizeof(struct tcphdr) - ETH_HLEN;
+       cm_node->tcp_cntxt.rcv_nxt = 0;
+       /* get a unique session ID , add thread_id to an upcounter to handle race */
+       atomic_inc(&cm_core->node_cnt);
+       atomic_inc(&cm_core->session_id);
+       cm_node->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+       cm_node->conn_type = cm_info->conn_type;
+       cm_node->apbvt_set = 0;
+       cm_node->accept_pend = 0;
+
+       cm_node->nesvnic = nesvnic;
+       /* get some device handles, for arp lookup */
+       nesdev = nesvnic->nesdev;
+       nesadapter = nesdev->nesadapter;
+
+       cm_node->loopbackpartner = NULL;
+       /* get the mac addr for the remote node */
+       arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+       if (arpindex < 0) {
+               kfree(cm_node);
+               nes_addr_send_arp(cm_info->rem_addr);
+               return NULL;
+       }
+
+       /* copy the mac addr to node context */
+       memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
+       nes_debug(NES_DBG_CM, "Remote mac addr from arp table:%02x,"
+                       " %02x, %02x, %02x, %02x, %02x\n",
+                       cm_node->rem_mac[0], cm_node->rem_mac[1],
+                       cm_node->rem_mac[2], cm_node->rem_mac[3],
+                       cm_node->rem_mac[4], cm_node->rem_mac[5]);
+
+       add_hte_node(cm_core, cm_node);
+       atomic_inc(&cm_nodes_created);
+
+       return cm_node;
+}
+
+
+/**
+ * add_ref_cm_node - destroy an instance of a cm node
+ */
+static int add_ref_cm_node(struct nes_cm_node *cm_node)
+{
+       atomic_inc(&cm_node->ref_count);
+       return 0;
+}
+
+
+/**
+ * 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)
+{
+       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;
+       struct nes_qp *nesqp;
+
+       if (!cm_node)
+               return -EINVAL;
+
+       spin_lock_irqsave(&cm_node->cm_core->ht_lock, flags);
+       if (atomic_dec_return(&cm_node->ref_count)) {
+               spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+               return 0;
+       }
+       list_del(&cm_node->list);
+       atomic_dec(&cm_core->ht_node_cnt);
+       spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+
+       /* if the node is destroyed before connection was accelerated */
+       if (!cm_node->accelerated && 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);
+       }
+
+       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);
+
+       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);
+               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);
+               }
+               kfree(recv_entry);
+               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+       }
+       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+
+       if (cm_node->listener) {
+               mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
+       } 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);
+               }
+       }
+
+       kfree(cm_node);
+       atomic_dec(&cm_core->node_cnt);
+       atomic_inc(&cm_nodes_destroyed);
+
+       return 0;
+}
+
+
+/**
+ * process_options
+ */
+static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet)
+{
+       u32 tmp;
+       u32 offset = 0;
+       union all_known_options *all_options;
+       char got_mss_option = 0;
+
+       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",
+                                               __FUNCTION__,
+                                               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;
+       }
+       if ((!got_mss_option) && (syn_packet))
+               cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+       return 0;
+}
+
+
+/**
+ * process_packet
+ */
+int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
+               struct nes_cm_core *cm_core)
+{
+       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;
+       }
+
+       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;
+
+                               create_event(cm_node, NES_CM_EVENT_ABORTED);
+                               break;
+
+               }
+               return -1;
+       }
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+
+       skb_pull(skb, ip_hdr(skb)->ihl << 2);
+       skb_pull(skb, tcph->doff << 2);
+
+       datasize = skb->len;
+       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);
+               }
+               return -1;
+       }
+
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+
+
+       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", __FUNCTION__, 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;
+               }
+       } 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) {
+               cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
+       }
+
+       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;
+               }
+       }
+
+       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;
+
+               }
+               if (datasize == 0)
+                       cm_node->tcp_cntxt.rcv_nxt ++;
+
+               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;
+
+                               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
+                               ret = send_mpa_request(cm_node);
+                               if (ret < 0)
+                                       return ret;
+               }
+       }
+
+       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;
+               }
+       }
+
+       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;
+               }
+       }
+
+       return ret;
+}
+
+
+/**
+ * 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_cm_listener *listener;
+       unsigned long flags;
+
+       nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
+               cm_info->loc_addr, cm_info->loc_port);
+
+       /* cannot have multiple matching listeners */
+       listener = find_listener(cm_core, htonl(cm_info->loc_addr),
+                       htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);
+       if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
+               /* find automatically incs ref count ??? */
+               atomic_dec(&listener->ref_count);
+               nes_debug(NES_DBG_CM, "Not creating listener since it already exists\n");
+               return NULL;
+       }
+
+       if (!listener) {
+               /* create a CM listen node (1/2 node to compare incoming traffic to) */
+               listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
+               if (!listener) {
+                       nes_debug(NES_DBG_CM, "Not creating listener memory allocation failed\n");
+                       return NULL;
+               }
+
+               memset(listener, 0, sizeof(struct nes_cm_listener));
+               listener->loc_addr = htonl(cm_info->loc_addr);
+               listener->loc_port = htons(cm_info->loc_port);
+               listener->reused_node = 0;
+
+               atomic_set(&listener->ref_count, 1);
+       }
+       /* pasive case */
+       /* find already inc'ed the ref count */
+       else {
+               listener->reused_node = 1;
+       }
+
+       listener->cm_id = cm_info->cm_id;
+       atomic_set(&listener->pend_accepts_cnt, 0);
+       listener->cm_core = cm_core;
+       listener->nesvnic = nesvnic;
+       atomic_inc(&cm_core->node_cnt);
+       atomic_inc(&cm_core->session_id);
+
+       listener->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+       listener->conn_type = cm_info->conn_type;
+       listener->backlog = cm_info->backlog;
+       listener->listener_state = NES_CM_LISTENER_ACTIVE_STATE;
+
+       if (!listener->reused_node) {
+               spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+               list_add(&listener->list, &cm_core->listen_list.list);
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+               atomic_inc(&cm_core->listen_node_cnt);
+       }
+
+       nes_debug(NES_DBG_CM, "Api - listen(): addr=0x%08X, port=0x%04x,"
+                       " listener = %p, backlog = %d, cm_id = %p.\n",
+                       cm_info->loc_addr, cm_info->loc_port,
+                       listener, listener->backlog, listener->cm_id);
+
+       return listener;
+}
+
+
+/**
+ * mini_cm_connect - make a connection node with params
+ */
+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)
+{
+       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);
+
+       /* create a CM connection node */
+       cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
+       if (!cm_node)
+               return NULL;
+
+       // 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);
+               if (loopbackremotelistener == NULL) {
+                       create_event(cm_node, NES_CM_EVENT_ABORTED);
+               } else {
+                       atomic_inc(&cm_loopbacks);
+                       loopback_cm_info = *cm_info;
+                       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->loopbackpartner = cm_node;
+                       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);
+
+                       // 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;
+
+                       create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
+               }
+               return cm_node;
+       }
+
+       /* 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);
+       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);
+
+       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;
+}
+
+
+/**
+ * mini_cm_accept - accept a connection
+ * This function is never called
+ */
+int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame,
+               struct nes_cm_node *cm_node)
+{
+       return 0;
+}
+
+
+/**
+ * mini_cm_reject - reject and teardown a connection
+ */
+int mini_cm_reject(struct nes_cm_core *cm_core,
+               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);
+
+       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;
+       }
+
+       return ret;
+}
+
+
+/**
+ * mini_cm_close
+ */
+int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+       int ret = 0;
+
+       if (!cm_core || !cm_node)
+               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;
+       }
+       cm_node->cm_id = NULL;
+       return ret;
+}
+
+
+/**
+ * recv_pkt - recv an ETHERNET packet, and process it through CM
+ * node state machine
+ */
+int 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;
+       }
+
+       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));
+       skb->len = ntohs(iph->tot_len);
+
+       nfo.loc_addr = ntohl(iph->daddr);
+       nfo.loc_port = ntohs(tcph->dest);
+       nfo.rem_addr = ntohl(iph->saddr);
+       nfo.rem_port = ntohs(tcph->source);
+
+       nes_debug(NES_DBG_CM, "Received packet: dest=0x%08X:0x%04X src=0x%08X:0x%04X\n",
+                       iph->daddr, tcph->dest, iph->saddr, tcph->source);
+
+       /* note: this call is going to increment cm_node ref count */
+       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");
+                       if (listener) {
+                               nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n");
+                               atomic_dec(&listener->ref_count);
+                       }
+                       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);
+                       }
+                       rem_ref_cm_node(cm_core, cm_node);
+                       ret = -1;
+                       goto out;
+               }
+               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;
+}
+
+
+/**
+ * nes_cm_alloc_core - allocate a top level instance of a cm core
+ */
+struct nes_cm_core *nes_cm_alloc_core(void)
+{
+       int i;
+
+       struct nes_cm_core *cm_core;
+       struct sk_buff *skb = NULL;
+
+       /* setup the CM core */
+       /* alloc top level core control structure */
+       cm_core = kzalloc(sizeof(*cm_core), GFP_KERNEL);
+       if (!cm_core)
+               return NULL;
+
+       INIT_LIST_HEAD(&cm_core->connected_nodes);
+       init_timer(&cm_core->tcp_timer);
+       cm_core->tcp_timer.function = nes_cm_timer_tick;
+
+       cm_core->mtu   = NES_CM_DEFAULT_MTU;
+       cm_core->state = NES_CM_STATE_INITED;
+       cm_core->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;
+
+       atomic_set(&cm_core->session_id, 0);
+       atomic_set(&cm_core->events_posted, 0);
+
+       /* init the packet lists */
+       skb_queue_head_init(&cm_core->tx_free_list);
+
+       for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
+               skb = dev_alloc_skb(cm_core->mtu);
+               if (!skb) {
+                       kfree(cm_core);
+                       return NULL;
+               }
+               /* add 'raw' skb to free frame list */
+               skb_queue_head(&cm_core->tx_free_list, skb);
+       }
+
+       cm_core->api = &nes_cm_api;
+
+       spin_lock_init(&cm_core->ht_lock);
+       spin_lock_init(&cm_core->listen_list_lock);
+
+       INIT_LIST_HEAD(&cm_core->listen_list.list);
+
+       nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);
+
+       nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");
+       cm_core->event_wq = create_singlethread_workqueue("nesewq");
+       cm_core->post_event = nes_cm_post_event;
+       nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");
+       cm_core->disconn_wq = create_singlethread_workqueue("nesdwq");
+
+       print_core(cm_core);
+       return cm_core;
+}
+
+
+/**
+ * mini_cm_dealloc_core - deallocate a top level instance of a cm core
+ */
+int mini_cm_dealloc_core(struct nes_cm_core *cm_core)
+{
+       nes_debug(NES_DBG_CM, "De-Alloc CM Core (%p)\n", cm_core);
+
+       if (!cm_core)
+               return -EINVAL;
+
+       barrier();
+
+       if (timer_pending(&cm_core->tcp_timer)) {
+               del_timer(&cm_core->tcp_timer);
+       }
+
+       destroy_workqueue(cm_core->event_wq);
+       destroy_workqueue(cm_core->disconn_wq);
+       nes_debug(NES_DBG_CM, "\n");
+       kfree(cm_core);
+
+       return 0;
+}
+
+
+/**
+ * mini_cm_get
+ */
+int mini_cm_get(struct nes_cm_core *cm_core)
+{
+       return cm_core->state;
+}
+
+
+/**
+ * mini_cm_set
+ */
+int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
+{
+       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;
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_init_tsa_conn setup HW; MPA frames must be
+ * successfully exchanged when this is called
+ */
+static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_node)
+{
+       int ret = 0;
+
+       if (!nesqp)
+               return -EINVAL;
+
+       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_IPV4 |
+                       NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |
+                       NES_QPCONTEXT_MISC_DROS);
+
+       if (cm_node->tcp_cntxt.snd_wscale || cm_node->tcp_cntxt.rcv_wscale)
+               nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WSCALE);
+
+       nesqp->nesqp_context->misc2 |= cpu_to_le32(64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);
+
+       nesqp->nesqp_context->mss |= cpu_to_le32(((u32)cm_node->tcp_cntxt.mss) << 16);
+
+       nesqp->nesqp_context->tcp_state_flow_label |= cpu_to_le32(
+                       (u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT);
+
+       nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+                       (cm_node->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &
+                       NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK);
+
+       nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+                       (cm_node->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &
+                       NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK);
+
+       nesqp->nesqp_context->keepalive = cpu_to_le32(0x80);
+       nesqp->nesqp_context->ts_recent = 0;
+       nesqp->nesqp_context->ts_age = 0;
+       nesqp->nesqp_context->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);
+       nesqp->nesqp_context->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+       nesqp->nesqp_context->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<
+                       cm_node->tcp_cntxt.rcv_wscale);
+       nesqp->nesqp_context->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->srtt = 0;
+       nesqp->nesqp_context->rttvar = cpu_to_le32(0x6);
+       nesqp->nesqp_context->ssthresh = cpu_to_le32(0x3FFFC000);
+       nesqp->nesqp_context->cwnd = cpu_to_le32(2*cm_node->tcp_cntxt.mss);
+       nesqp->nesqp_context->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+       nesqp->nesqp_context->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->max_snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);
+
+       nes_debug(NES_DBG_CM, "QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X,"
+                       " Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",
+                       nesqp->hwqp.qp_id, le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
+                       le32_to_cpu(nesqp->nesqp_context->snd_nxt),
+                       cm_node->tcp_cntxt.mss, le32_to_cpu(nesqp->nesqp_context->pd_index_wscale),
+                       le32_to_cpu(nesqp->nesqp_context->rcv_wnd),
+                       le32_to_cpu(nesqp->nesqp_context->misc));
+       nes_debug(NES_DBG_CM, "  snd_wnd  = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->snd_wnd));
+       nes_debug(NES_DBG_CM, "  snd_cwnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->cwnd));
+       nes_debug(NES_DBG_CM, "  max_swnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->max_snd_wnd));
+
+       nes_debug(NES_DBG_CM, "Change cm_node state to TSA\n");
+       cm_node->state = NES_CM_STATE_TSA;
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_disconn
+ */
+int nes_cm_disconn(struct nes_qp *nesqp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesqp->lock, flags);
+       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 {
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+               nes_rem_ref(&nesqp->ibqp);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_disconnect_worker
+ */
+void nes_disconnect_worker(struct work_struct *work)
+{
+       struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+
+       nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
+                       nesqp->last_aeq, nesqp->hwqp.qp_id);
+       nes_cm_disconn_true(nesqp);
+}
+
+
+/**
+ * nes_cm_disconn_true
+ */
+int nes_cm_disconn_true(struct nes_qp *nesqp)
+{
+       unsigned long flags;
+       int ret = 0;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_vnic *nesvnic;
+       u16 last_ae;
+       u8 original_hw_tcp_state;
+       u8 original_ibqp_state;
+       u8 issued_disconnect_reset = 0;
+
+       if (!nesqp) {
+               nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");
+               return -1;
+       }
+
+       spin_lock_irqsave(&nesqp->lock, flags);
+       cm_id = nesqp->cm_id;
+       /* make sure we havent already closed this connection */
+       if (!cm_id) {
+               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;
+       }
+
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       nes_debug(NES_DBG_CM, "Disconnecting QP%u\n", nesqp->hwqp.qp_id);
+
+       original_hw_tcp_state = nesqp->hw_tcp_state;
+       original_ibqp_state   = nesqp->ibqp_state;
+       last_ae = nesqp->last_aeq;
+
+
+       nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state);
+
+       if ((nesqp->cm_id) && (cm_id->event_handler)) {
+               if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                               ((original_ibqp_state == IB_QPS_RTS) &&
+                               (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                       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 {
+                               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));
+
+                       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);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+               }
+
+               nesqp->disconn_pending = 0;
+               /* There might have been another AE while the lock was released */
+               original_hw_tcp_state = nesqp->hw_tcp_state;
+               original_ibqp_state   = nesqp->ibqp_state;
+               last_ae = nesqp->last_aeq;
+
+               if ((issued_disconnect_reset == 0) && (nesqp->cm_id) &&
+                               ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+                                (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
+                                (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
+                                (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                       atomic_inc(&cm_closes);
+                       nesqp->cm_id = NULL;
+                       nesqp->in_disconnect = 0;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_disconnect(nesqp, 1);
+
+                       cm_id->provider_data = nesqp;
+                       /* Send up the close complete event */
+                       cm_event.event = IW_CM_EVENT_CLOSE;
+                       cm_event.status = IW_CM_EVENT_STATUS_OK;
+                       cm_event.provider_data = cm_id->provider_data;
+                       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;
+
+                       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);
+                       }
+
+                       cm_id->rem_ref(cm_id);
+
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       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 {
+                               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);
+                       }
+               }
+       } else {
+               nesqp->disconn_pending = 0;
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+       }
+       nes_rem_ref(&nesqp->ibqp);
+
+       return 0;
+}
+
+
+/**
+ * nes_disconnect
+ */
+int nes_disconnect(struct nes_qp *nesqp, int abrupt)
+{
+       int ret = 0;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       if (!nesvnic)
+               return -EINVAL;
+
+       nesdev = nesvnic->nesdev;
+
+       nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
+                       atomic_read(&nesvnic->netdev->refcnt));
+
+       if (nesqp->active_conn) {
+
+               /* indicate this connection is NOT active */
+               nesqp->active_conn = 0;
+       } else {
+               /* Need to free the Last Streaming Mode Message */
+               if (nesqp->ietf_frame) {
+                       pci_free_consistent(nesdev->pcidev,
+                                       nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+                                       nesqp->ietf_frame, nesqp->ietf_frame_pbase);
+               }
+       }
+
+       /* close the CM node down if it is still active */
+       if (nesqp->cm_node) {
+               nes_debug(NES_DBG_CM, "Call close API\n");
+
+               g_cm_core->api->close(g_cm_core, nesqp->cm_node);
+               nesqp->cm_node = NULL;
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_accept
+ */
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+       u64 u64temp;
+       struct ib_qp *ibqp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_adapter *adapter;
+       struct ib_qp_attr attr;
+       struct iw_cm_event cm_event;
+       struct nes_hw_qp_wqe *wqe;
+       struct nes_v4_quad nes_quad;
+       int ret;
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+
+       /* get all our handles */
+       nesqp = to_nesqp(ibqp);
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       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;
+
+       /* associate the node with the QP */
+       nesqp->cm_node = (void *)cm_node;
+
+       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n",
+                       nesqp->hwqp.qp_id, cm_node, jiffies);
+       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;
+               }
+
+
+               /* 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);
+
+               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;
+
+               /* 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 */
+       nesqp->cm_id = cm_id;
+       cm_node->cm_id = cm_id;
+
+       /*  nesqp->cm_node = (void *)cm_id->provider_data; */
+       cm_id->provider_data = nesqp;
+       nesqp->active_conn   = 0;
+
+       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->misc2 |= cpu_to_le32(
+                       (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,
+                       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));
+       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;
+
+       /* Produce hash key */
+       nesqp->hte_index = cpu_to_be32(
+                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 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 &= 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,
+                       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));
+
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+       /* notify OF layer that accept event was successfull */
+       cm_id->add_ref(cm_id);
+
+       cm_event.event = IW_CM_EVENT_ESTABLISHED;
+       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.provider_data = (void *)nesqp;
+       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;
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (cm_node->loopbackpartner) {
+               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);
+               create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
+       }
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+
+       return 0;
+}
+
+
+/**
+ * nes_reject
+ */
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+       struct nes_cm_node *cm_node;
+       struct nes_cm_core *cm_core;
+
+       atomic_inc(&cm_rejects);
+       cm_node = (struct nes_cm_node *) cm_id->provider_data;
+       cm_core = cm_node->cm_core;
+       cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
+
+       strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
+       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.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;
+}
+
+
+/**
+ * nes_connect
+ * setup and launch cm connect node
+ */
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+       struct ib_qp *ibqp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_cm_info cm_info;
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+       nesqp = to_nesqp(ibqp);
+       if (!nesqp)
+               return -EINVAL;
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       if (!nesvnic)
+               return -EINVAL;
+       nesdev  = nesvnic->nesdev;
+       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;
+
+       /* set qp as having an active connection */
+       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);
+
+       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);
+
+       /* 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.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);
+       if (!cm_node) {
+               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;
+               cm_id->rem_ref(cm_id);
+               return -ENOMEM;
+       }
+
+       cm_node->apbvt_set = 1;
+       nesqp->cm_node = cm_node;
+
+       return 0;
+}
+
+
+/**
+ * nes_create_listen
+ */
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+       struct nes_vnic *nesvnic;
+       struct nes_cm_listener *cm_node;
+       struct nes_cm_info cm_info;
+       struct nes_adapter *adapter;
+       int err;
+
+
+       nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
+                       cm_id, ntohs(cm_id->local_addr.sin_port));
+
+       nesvnic = to_nesvnic(cm_id->device);
+       if (!nesvnic)
+               return -EINVAL;
+       adapter = nesvnic->nesdev->nesadapter;
+       nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
+                       nesvnic, nesvnic->netdev, nesvnic->netdev->name);
+
+       nes_debug(NES_DBG_CM, "nesvnic->local_ipaddr=0x%08x, sin_addr.s_addr=0x%08x\n",
+                       nesvnic->local_ipaddr, cm_id->local_addr.sin_addr.s_addr);
+
+       /* setup listen params in our api call struct */
+       cm_info.loc_addr = nesvnic->local_ipaddr;
+       cm_info.loc_port = cm_id->local_addr.sin_port;
+       cm_info.backlog = backlog;
+       cm_info.cm_id = cm_id;
+
+       cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+
+       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",
+                               __FUNCTION__, __LINE__);
+               return -ENOMEM;
+       }
+
+       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);
+               if (err) {
+                       printk("nes_manage_apbvt call returned %d.\n", err);
+                       g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
+                       return err;
+               }
+               cm_listens_created++;
+       }
+
+       cm_id->add_ref(cm_id);
+       cm_id->provider_data = (void *)cm_node;
+
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_listen
+ */
+int nes_destroy_listen(struct iw_cm_id *cm_id)
+{
+       if (cm_id->provider_data)
+               g_cm_core->api->stop_listener(g_cm_core, cm_id->provider_data);
+       else
+               nes_debug(NES_DBG_CM, "cm_id->provider_data was NULL\n");
+
+       cm_id->rem_ref(cm_id);
+
+       return 0;
+}
+
+
+/**
+ * nes_cm_recv
+ */
+int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
+{
+       cm_packets_received++;
+       if ((g_cm_core) && (g_cm_core->api)) {
+               g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
+       } else {
+               nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
+                               " cm is not setup properly.\n");
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_cm_start
+ * Start and init a cm core module
+ */
+int nes_cm_start(void)
+{
+       nes_debug(NES_DBG_CM, "\n");
+       /* create the primary CM core, pass this handle to subsequent core inits */
+       g_cm_core = nes_cm_alloc_core();
+       if (g_cm_core) {
+               return 0;
+       } else {
+               return -ENOMEM;
+       }
+}
+
+
+/**
+ * nes_cm_stop
+ * stop and dealloc all cm core instances
+ */
+int nes_cm_stop(void)
+{
+       g_cm_core->api->destroy_cm_core(g_cm_core);
+       return 0;
+}
+
+
+/**
+ * cm_event_connected
+ * handle a connected event, setup QPs and HW
+ */
+void cm_event_connected(struct nes_cm_event *event)
+{
+       u64 u64temp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_adapter *nesadapter;
+       struct ib_qp_attr attr;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_hw_qp_wqe *wqe;
+       struct nes_v4_quad nes_quad;
+       int ret;
+
+       /* get all our handles */
+       cm_node = event->cm_node;
+       cm_id = cm_node->cm_id;
+       nes_debug(NES_DBG_CM, "cm_event_connected - %p - cm_id = %p\n", cm_node, cm_id);
+       nesqp = (struct nes_qp *)cm_id->provider_data;
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       nesdev = nesvnic->nesdev;
+       nesadapter = nesdev->nesadapter;
+
+       if (nesqp->destroyed) {
+               return;
+       }
+       atomic_inc(&cm_connecteds);
+       nes_debug(NES_DBG_CM, "QP%u attempting to connect to  0x%08X:0x%04X on"
+                       " local port 0x%04X. jiffies = %lu.\n",
+                       nesqp->hwqp.qp_id,
+                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
+                       ntohs(cm_id->remote_addr.sin_port),
+                       ntohs(cm_id->local_addr.sin_port),
+                       jiffies);
+
+       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->misc2 |= cpu_to_le32(
+                       (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, 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);
+
+       /* 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);
+               }
+#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.TcpPorts[0] = cm_id->remote_addr.sin_port;
+       nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
+
+       /* Produce hash key */
+       nesqp->hte_index = cpu_to_be32(
+                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+       nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
+                       nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
+
+       nesqp->hte_index &= nesadapter->hte_index_mask;
+       nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
+
+       nesqp->ietf_frame = &cm_node->mpa_frame;
+       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;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr.sin_family = AF_INET;
+       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.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",
+                               __FUNCTION__, __LINE__, ret);
+       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n",
+                       nesqp->hwqp.qp_id, jiffies );
+
+       nes_rem_ref(&nesqp->ibqp);
+
+       return;
+}
+
+
+/**
+ * cm_event_connect_error
+ */
+void cm_event_connect_error(struct nes_cm_event *event)
+{
+       struct nes_qp *nesqp;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       /* struct nes_cm_info cm_info; */
+       int ret;
+
+       if (!event->cm_node)
+               return;
+
+       cm_id = event->cm_node->cm_id;
+       if (!cm_id) {
+               return;
+       }
+
+       nes_debug(NES_DBG_CM, "cm_node=%p, cm_id=%p\n", event->cm_node, cm_id);
+       nesqp = cm_id->provider_data;
+
+       if (!nesqp) {
+               return;
+       }
+
+       /* notify OF layer about this connection error event */
+       /* cm_id->rem_ref(cm_id); */
+       nesqp->cm_id = NULL;
+       cm_id->provider_data = NULL;
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = IW_CM_EVENT_STATUS_REJECTED;
+       cm_event.provider_data = cm_id->provider_data;
+       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, "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",
+                               __FUNCTION__, __LINE__, ret);
+       nes_rem_ref(&nesqp->ibqp);
+               cm_id->rem_ref(cm_id);
+
+       return;
+}
+
+
+/**
+ * cm_event_reset
+ */
+void cm_event_reset(struct nes_cm_event *event)
+{
+       struct nes_qp *nesqp;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       /* struct nes_cm_info cm_info; */
+       int ret;
+
+       if (!event->cm_node)
+               return;
+
+       if (!event->cm_node->cm_id)
+               return;
+
+       cm_id = event->cm_node->cm_id;
+
+       nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);
+       nesqp = cm_id->provider_data;
+
+       nesqp->cm_id = NULL;
+       /* cm_id->provider_data = NULL; */
+       cm_event.event = IW_CM_EVENT_DISCONNECT;
+       cm_event.status = IW_CM_EVENT_STATUS_RESET;
+       cm_event.provider_data = cm_id->provider_data;
+       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;
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+
+
+       /* notify OF layer about this connection error event */
+       cm_id->rem_ref(cm_id);
+
+       return;
+}
+
+
+/**
+ * cm_event_mpa_req
+ */
+void cm_event_mpa_req(struct nes_cm_event *event)
+{
+       struct iw_cm_id   *cm_id;
+       struct iw_cm_event cm_event;
+       int ret;
+       struct nes_cm_node *cm_node;
+
+       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_REQUEST;
+       cm_event.status = IW_CM_EVENT_STATUS_OK;
+       cm_event.provider_data = (void *)cm_node;
+
+       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;
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+
+       return;
+}
+
+
+static void nes_cm_event_handler(struct work_struct *);
+
+/**
+ * nes_cm_post_event
+ * post an event to the cm event handler
+ */
+int nes_cm_post_event(struct nes_cm_event *event)
+{
+       atomic_inc(&event->cm_node->cm_core->events_posted);
+       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);
+
+       queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
+
+       nes_debug(NES_DBG_CM, "Exit\n");
+       return 0;
+}
+
+
+/**
+ * nes_cm_event_handler
+ * worker function to handle cm events
+ * will free instance of nes_cm_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_core *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));
+
+       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");
+                       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);
+       event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);
+       rem_ref_cm_node(cm_core, event->cm_node);
+       kfree(event);
+
+       return;
+}
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
new file mode 100644 (file)
index 0000000..a59f0a7
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_CM_H
+#define NES_CM_H
+
+#define QUEUE_EVENTS
+
+#define NES_MANAGE_APBVT_DEL 0
+#define NES_MANAGE_APBVT_ADD 1
+
+/* IETF MPA -- defines, enums, structs */
+#define IEFT_MPA_KEY_REQ  "MPA ID Req Frame"
+#define IEFT_MPA_KEY_REP  "MPA ID Rep Frame"
+#define IETF_MPA_KEY_SIZE 16
+#define IETF_MPA_VERSION  1
+
+enum ietf_mpa_flags {
+       IETF_MPA_FLAGS_MARKERS = 0x80,  /* receive Markers */
+       IETF_MPA_FLAGS_CRC     = 0x40,  /* receive Markers */
+       IETF_MPA_FLAGS_REJECT  = 0x20,  /* Reject */
+};
+
+struct ietf_mpa_frame {
+       u8 key[IETF_MPA_KEY_SIZE];
+       u8 flags;
+       u8 rev;
+       __be16 priv_data_len;
+       u8 priv_data[0];
+};
+
+#define ietf_mpa_req_resp_frame ietf_mpa_frame
+
+struct nes_v4_quad {
+       u32 rsvd0;
+       __le32 DstIpAdrIndex;   /* Only most significant 5 bits are valid */
+       __be32 SrcIpadr;
+       __be16 TcpPorts[2];             /* src is low, dest is high */
+};
+
+struct nes_cm_node;
+enum nes_timer_type {
+       NES_TIMER_TYPE_SEND,
+       NES_TIMER_TYPE_RECV,
+       NES_TIMER_NODE_CLEANUP,
+       NES_TIMER_TYPE_CLOSE,
+};
+
+#define MAX_NES_IFS 4
+
+#define SET_ACK 1
+#define SET_SYN 2
+#define SET_FIN 4
+#define SET_RST 8
+
+struct option_base {
+       u8 optionnum;
+       u8 length;
+};
+
+enum option_numbers {
+       OPTION_NUMBER_END,
+       OPTION_NUMBER_NONE,
+       OPTION_NUMBER_MSS,
+       OPTION_NUMBER_WINDOW_SCALE,
+       OPTION_NUMBER_SACK_PERM,
+       OPTION_NUMBER_SACK,
+       OPTION_NUMBER_WRITE0 = 0xbc
+};
+
+struct option_mss {
+       u8 optionnum;
+       u8 length;
+       __be16 mss;
+};
+
+struct option_windowscale {
+       u8 optionnum;
+       u8 length;
+       u8 shiftcount;
+};
+
+union all_known_options {
+       char as_end;
+       struct option_base as_base;
+       struct option_mss as_mss;
+       struct option_windowscale as_windowscale;
+};
+
+struct nes_timer_entry {
+       struct list_head list;
+       unsigned long timetosend;       /* jiffies */
+       struct sk_buff *skb;
+       u32 type;
+       u32 retrycount;
+       u32 retranscount;
+       u32 context;
+       u32 seq_num;
+       u32 send_retrans;
+       int close_when_complete;
+       struct net_device *netdev;
+};
+
+#define NES_DEFAULT_RETRYS  64
+#define NES_DEFAULT_RETRANS 8
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define NES_RETRY_TIMEOUT   (1000*HZ/1000)
+#else
+#define NES_RETRY_TIMEOUT   (3000*HZ/1000)
+#endif
+#define NES_SHORT_TIME      (10)
+#define NES_LONG_TIME       (2000*HZ/1000)
+
+#define NES_CM_HASHTABLE_SIZE         1024
+#define NES_CM_TCP_TIMER_INTERVAL     3000
+#define NES_CM_DEFAULT_MTU            1540
+#define NES_CM_DEFAULT_FRAME_CNT      10
+#define NES_CM_THREAD_STACK_SIZE      256
+#define NES_CM_DEFAULT_RCV_WND        64240    // before we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALED 256960  // after we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALE  2
+#define NES_CM_DEFAULT_FREE_PKTS      0x000A
+#define NES_CM_FREE_PKT_LO_WATERMARK  2
+
+#define NES_CM_DEFAULT_MSS   536
+
+#define NES_CM_DEF_SEQ       0x159bf75f
+#define NES_CM_DEF_LOCAL_ID  0x3b47
+
+#define NES_CM_DEF_SEQ2      0x18ed5740
+#define NES_CM_DEF_LOCAL_ID2 0xb807
+
+typedef u32 nes_addr_t;
+
+#define nes_cm_tsa_context nes_qp_context
+
+struct nes_qp;
+
+/* cm node transition states */
+enum nes_cm_node_state {
+       NES_CM_STATE_UNKNOWN,
+       NES_CM_STATE_INITED,
+       NES_CM_STATE_LISTENING,
+       NES_CM_STATE_SYN_RCVD,
+       NES_CM_STATE_SYN_SENT,
+       NES_CM_STATE_ONE_SIDE_ESTABLISHED,
+       NES_CM_STATE_ESTABLISHED,
+       NES_CM_STATE_ACCEPTING,
+       NES_CM_STATE_MPAREQ_SENT,
+       NES_CM_STATE_TSA,
+       NES_CM_STATE_FIN_WAIT1,
+       NES_CM_STATE_FIN_WAIT2,
+       NES_CM_STATE_CLOSE_WAIT,
+       NES_CM_STATE_TIME_WAIT,
+       NES_CM_STATE_LAST_ACK,
+       NES_CM_STATE_CLOSING,
+       NES_CM_STATE_CLOSED
+};
+
+/* type of nes connection */
+enum nes_cm_conn_type {
+       NES_CM_IWARP_CONN_TYPE,
+};
+
+/* CM context params */
+struct nes_cm_tcp_context {
+       u8  client;
+
+       u32 loc_seq_num;
+       u32 loc_ack_num;
+       u32 rem_ack_num;
+       u32 rcv_nxt;
+
+       u32 loc_id;
+       u32 rem_id;
+
+       u32 snd_wnd;
+       u32 max_snd_wnd;
+
+       u32 rcv_wnd;
+       u32 mss;
+       u8  snd_wscale;
+       u8  rcv_wscale;
+
+       struct nes_cm_tsa_context tsa_cntxt;
+       struct timeval            sent_ts;
+};
+
+
+enum nes_cm_listener_state {
+       NES_CM_LISTENER_PASSIVE_STATE=1,
+       NES_CM_LISTENER_ACTIVE_STATE=2,
+       NES_CM_LISTENER_EITHER_STATE=3
+};
+
+struct nes_cm_listener {
+       struct list_head           list;
+       u64                        session_id;
+       struct nes_cm_core         *cm_core;
+       u8                         loc_mac[ETH_ALEN];
+       nes_addr_t                 loc_addr;
+       u16                        loc_port;
+       struct iw_cm_id            *cm_id;
+       enum nes_cm_conn_type      conn_type;
+       atomic_t                   ref_count;
+       struct nes_vnic            *nesvnic;
+       atomic_t                   pend_accepts_cnt;
+       int                        backlog;
+       enum nes_cm_listener_state listener_state;
+       u32                        reused_node;
+};
+
+/* per connection node and node state information */
+struct nes_cm_node {
+       u64                       session_id;
+       u32                       hashkey;
+
+       nes_addr_t                loc_addr, rem_addr;
+       u16                       loc_port, rem_port;
+
+       u8                        loc_mac[ETH_ALEN];
+       u8                        rem_mac[ETH_ALEN];
+
+       enum nes_cm_node_state    state;
+       struct nes_cm_tcp_context tcp_cntxt;
+       struct nes_cm_core        *cm_core;
+       struct sk_buff_head       resend_list;
+       atomic_t                  ref_count;
+       struct net_device         *netdev;
+
+       struct nes_cm_node        *loopbackpartner;
+       struct list_head          retrans_list;
+       spinlock_t                retrans_list_lock;
+       struct list_head          recv_list;
+       spinlock_t                recv_list_lock;
+
+       int                       send_write0;
+       union {
+               struct ietf_mpa_frame mpa_frame;
+               u8                    mpa_frame_buf[NES_CM_DEFAULT_MTU];
+       };
+       u16                       mpa_frame_size;
+       struct iw_cm_id           *cm_id;
+       struct list_head          list;
+       int                       accelerated;
+       struct nes_cm_listener    *listener;
+       enum nes_cm_conn_type     conn_type;
+       struct nes_vnic           *nesvnic;
+       int                       apbvt_set;
+       int                       accept_pend;
+};
+
+/* structure for client or CM to fill when making CM api calls. */
+/*     - only need to set relevant data, based on op. */
+struct nes_cm_info {
+       union {
+               struct iw_cm_id   *cm_id;
+               struct net_device *netdev;
+       };
+
+       u16 loc_port;
+       u16 rem_port;
+       nes_addr_t loc_addr;
+       nes_addr_t rem_addr;
+
+       enum nes_cm_conn_type  conn_type;
+       int backlog;
+};
+
+/* CM event codes */
+enum  nes_cm_event_type {
+       NES_CM_EVENT_UNKNOWN,
+       NES_CM_EVENT_ESTABLISHED,
+       NES_CM_EVENT_MPA_REQ,
+       NES_CM_EVENT_MPA_CONNECT,
+       NES_CM_EVENT_MPA_ACCEPT,
+       NES_CM_EVENT_MPA_ESTABLISHED,
+       NES_CM_EVENT_CONNECTED,
+       NES_CM_EVENT_CLOSED,
+       NES_CM_EVENT_RESET,
+       NES_CM_EVENT_DROPPED_PKT,
+       NES_CM_EVENT_CLOSE_IMMED,
+       NES_CM_EVENT_CLOSE_HARD,
+       NES_CM_EVENT_CLOSE_CLEAN,
+       NES_CM_EVENT_ABORTED,
+       NES_CM_EVENT_SEND_FIRST
+};
+
+/* event to post to CM event handler */
+struct nes_cm_event {
+       enum nes_cm_event_type type;
+
+       struct nes_cm_info cm_info;
+       struct work_struct event_work;
+       struct nes_cm_node *cm_node;
+};
+
+struct nes_cm_core {
+       enum nes_cm_node_state  state;
+       atomic_t                session_id;
+
+       atomic_t                listen_node_cnt;
+       struct nes_cm_node      listen_list;
+       spinlock_t              listen_list_lock;
+
+       u32                     mtu;
+       u32                     free_tx_pkt_max;
+       u32                     rx_pkt_posted;
+       struct sk_buff_head     tx_free_list;
+       atomic_t                ht_node_cnt;
+       struct list_head        connected_nodes;
+       /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
+       spinlock_t              ht_lock;
+
+       struct timer_list       tcp_timer;
+
+       struct nes_cm_ops       *api;
+
+       int (*post_event)(struct nes_cm_event *event);
+       atomic_t                events_posted;
+       struct workqueue_struct *event_wq;
+       struct workqueue_struct *disconn_wq;
+
+       atomic_t                node_cnt;
+       u64                     aborted_connects;
+       u32                     options;
+
+       struct nes_cm_node      *current_listen_node;
+};
+
+
+#define NES_CM_SET_PKT_SIZE        (1 << 1)
+#define NES_CM_SET_FREE_PKT_Q_SIZE (1 << 2)
+
+/* CM ops/API for client interface */
+struct nes_cm_ops {
+       int (*accelerated)(struct nes_cm_core *, struct nes_cm_node *);
+       struct nes_cm_listener * (*listen)(struct nes_cm_core *, struct nes_vnic *,
+                       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_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 *,
+                       struct sk_buff *);
+       int (*destroy_cm_core)(struct nes_cm_core *);
+       int (*get)(struct nes_cm_core *);
+       int (*set)(struct nes_cm_core *, u32, u32);
+};
+
+
+int send_mpa_request(struct nes_cm_node *);
+struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+               void *, u32, void *, u32, u8);
+int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *,
+               enum nes_timer_type, int, int);
+void nes_cm_timer_tick(unsigned long);
+int send_syn(struct nes_cm_node *, u32);
+int send_reset(struct nes_cm_node *);
+int send_ack(struct nes_cm_node *);
+int send_fin(struct nes_cm_node *, struct sk_buff *);
+struct sk_buff *get_free_pkt(struct nes_cm_node *);
+int process_packet(struct nes_cm_node *, struct sk_buff *, struct nes_cm_core *);
+
+struct nes_cm_node * mini_cm_connect(struct nes_cm_core *,
+               struct nes_vnic *, struct ietf_mpa_frame *, struct nes_cm_info *);
+int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
+int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
+struct nes_cm_core *mini_cm_alloc_core(struct nes_cm_info *);
+int mini_cm_dealloc_core(struct nes_cm_core *);
+int mini_cm_get(struct nes_cm_core *);
+int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+int nes_cm_disconn(struct nes_qp *);
+void nes_disconnect_worker(struct work_struct *);
+int nes_cm_disconn_true(struct nes_qp *);
+int nes_disconnect(struct nes_qp *, int);
+
+int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_reject(struct iw_cm_id *, const void *, u8);
+int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_create_listen(struct iw_cm_id *, int);
+int nes_destroy_listen(struct iw_cm_id *);
+
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+int nes_cm_start(void);
+int nes_cm_stop(void);
+
+/* CM event handler functions */
+void cm_event_connected(struct nes_cm_event *);
+void cm_event_connect_error(struct nes_cm_event *);
+void cm_event_reset(struct nes_cm_event *);
+void cm_event_mpa_req(struct nes_cm_event *);
+int nes_cm_post_event(struct nes_cm_event *);
+
+#endif                 /* NES_CM_H */
diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h
new file mode 100644 (file)
index 0000000..da9daba
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef NES_CONTEXT_H
+#define NES_CONTEXT_H
+
+struct nes_qp_context {
+       __le32   misc;
+       __le32   cqs;
+       __le32   sq_addr_low;
+       __le32   sq_addr_high;
+       __le32   rq_addr_low;
+       __le32   rq_addr_high;
+       __le32   misc2;
+       __le16   tcpPorts[2];
+       __le32   ip0;
+       __le32   ip1;
+       __le32   ip2;
+       __le32   ip3;
+       __le32   mss;
+       __le32   arp_index_vlan;
+       __le32   tcp_state_flow_label;
+       __le32   pd_index_wscale;
+       __le32   keepalive;
+       u32   ts_recent;
+       u32   ts_age;
+       __le32   snd_nxt;
+       __le32   snd_wnd;
+       __le32   rcv_nxt;
+       __le32   rcv_wnd;
+       __le32   snd_max;
+       __le32   snd_una;
+       u32   srtt;
+       __le32   rttvar;
+       __le32   ssthresh;
+       __le32   cwnd;
+       __le32   snd_wl1;
+       __le32   snd_wl2;
+       __le32   max_snd_wnd;
+       __le32   ts_val_delta;
+       u32   retransmit;
+       u32   probe_cnt;
+       u32   hte_index;
+       __le32   q2_addr_low;
+       __le32   q2_addr_high;
+       __le32   ird_index;
+       u32   Rsvd3;
+       __le32   ird_ord_sizes;
+       u32   mrkr_offset;
+       __le32   aeq_token_low;
+       __le32   aeq_token_high;
+};
+
+/* QP Context Misc Field */
+
+#define NES_QPCONTEXT_MISC_IWARP_VER_MASK    0x00000003
+#define NES_QPCONTEXT_MISC_IWARP_VER_SHIFT   0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_MASK     0x000000C0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_SHIFT    6
+#define NES_QPCONTEXT_MISC_RQ_SIZE_MASK      0x00000300
+#define NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT     8
+#define NES_QPCONTEXT_MISC_SQ_SIZE_MASK      0x00000c00
+#define NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT     10
+#define NES_QPCONTEXT_MISC_PCI_FCN_MASK      0x00007000
+#define NES_QPCONTEXT_MISC_PCI_FCN_SHIFT     12
+#define NES_QPCONTEXT_MISC_DUP_ACKS_MASK     0x00070000
+#define NES_QPCONTEXT_MISC_DUP_ACKS_SHIFT    16
+
+enum nes_qp_context_misc_bits {
+       NES_QPCONTEXT_MISC_RX_WQE_SIZE         = 0x00000004,
+       NES_QPCONTEXT_MISC_IPV4                = 0x00000008,
+       NES_QPCONTEXT_MISC_DO_NOT_FRAG         = 0x00000010,
+       NES_QPCONTEXT_MISC_INSERT_VLAN         = 0x00000020,
+       NES_QPCONTEXT_MISC_DROS                = 0x00008000,
+       NES_QPCONTEXT_MISC_WSCALE              = 0x00080000,
+       NES_QPCONTEXT_MISC_KEEPALIVE           = 0x00100000,
+       NES_QPCONTEXT_MISC_TIMESTAMP           = 0x00200000,
+       NES_QPCONTEXT_MISC_SACK                = 0x00400000,
+       NES_QPCONTEXT_MISC_RDMA_WRITE_EN       = 0x00800000,
+       NES_QPCONTEXT_MISC_RDMA_READ_EN        = 0x01000000,
+       NES_QPCONTEXT_MISC_WBIND_EN            = 0x10000000,
+       NES_QPCONTEXT_MISC_FAST_REGISTER_EN    = 0x20000000,
+       NES_QPCONTEXT_MISC_PRIV_EN             = 0x40000000,
+       NES_QPCONTEXT_MISC_NO_NAGLE            = 0x80000000
+};
+
+enum nes_qp_acc_wq_sizes {
+       HCONTEXT_TSA_WQ_SIZE_4 = 0,
+       HCONTEXT_TSA_WQ_SIZE_32 = 1,
+       HCONTEXT_TSA_WQ_SIZE_128 = 2,
+       HCONTEXT_TSA_WQ_SIZE_512 = 3
+};
+
+/* QP Context Misc2 Fields */
+#define NES_QPCONTEXT_MISC2_TTL_MASK            0x000000ff
+#define NES_QPCONTEXT_MISC2_TTL_SHIFT           0
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_MASK      0x000000ff
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_SHIFT     0
+#define NES_QPCONTEXT_MISC2_LIMIT_MASK          0x00000300
+#define NES_QPCONTEXT_MISC2_LIMIT_SHIFT         8
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_MASK      0x0000fc00
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT     10
+#define NES_QPCONTEXT_MISC2_SRC_IP_MASK         0x001f0000
+#define NES_QPCONTEXT_MISC2_SRC_IP_SHIFT        16
+#define NES_QPCONTEXT_MISC2_TOS_MASK            0xff000000
+#define NES_QPCONTEXT_MISC2_TOS_SHIFT           24
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_MASK  0xff000000
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_SHIFT 24
+
+/* QP Context Tcp State/Flow Label Fields */
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_MASK   0x000fffff
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_SHIFT  0
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_MASK    0xf0000000
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT   28
+
+enum nes_qp_tcp_state {
+       NES_QPCONTEXT_TCPSTATE_CLOSED = 1,
+       NES_QPCONTEXT_TCPSTATE_EST = 5,
+       NES_QPCONTEXT_TCPSTATE_TIME_WAIT = 11,
+};
+
+/* QP Context PD Index/wscale Fields */
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK  0x0000000f
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT 0
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK  0x00000f00
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT 8
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_MASK     0xffff0000
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_SHIFT    16
+
+/* QP Context Keepalive Fields */
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_MASK      0x0000ffff
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_SHIFT     0
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_MASK  0x00ff0000
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_SHIFT 16
+#define NES_QPCONTEXT_KEEPALIVE_INTV_MASK       0xff000000
+#define NES_QPCONTEXT_KEEPALIVE_INTV_SHIFT      24
+
+/* QP Context ORD/IRD Fields */
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_MASK       0x0000007f
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_SHIFT      0
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK       0x00030000
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT      16
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_MASK    0x30000000
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT   28
+
+enum nes_ord_ird_bits {
+       NES_QPCONTEXT_ORDIRD_WRPDU                   = 0x02000000,
+       NES_QPCONTEXT_ORDIRD_LSMM_PRESENT            = 0x04000000,
+       NES_QPCONTEXT_ORDIRD_ALSMM                   = 0x08000000,
+       NES_QPCONTEXT_ORDIRD_AAH                     = 0x40000000,
+       NES_QPCONTEXT_ORDIRD_RNMC                    = 0x80000000
+};
+
+enum nes_iwarp_qp_state {
+       NES_QPCONTEXT_IWARP_STATE_NONEXIST  = 0,
+       NES_QPCONTEXT_IWARP_STATE_IDLE      = 1,
+       NES_QPCONTEXT_IWARP_STATE_RTS       = 2,
+       NES_QPCONTEXT_IWARP_STATE_CLOSING   = 3,
+       NES_QPCONTEXT_IWARP_STATE_TERMINATE = 5,
+       NES_QPCONTEXT_IWARP_STATE_ERROR     = 6
+};
+
+
+#endif         /* NES_CONTEXT_H */
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
new file mode 100644 (file)
index 0000000..7c4c0fb
--- /dev/null
@@ -0,0 +1,3080 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, 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
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+
+#include "nes.h"
+
+u32 crit_err_count = 0;
+u32 int_mod_timer_init;
+u32 int_mod_cq_depth_256;
+u32 int_mod_cq_depth_128;
+u32 int_mod_cq_depth_32;
+u32 int_mod_cq_depth_24;
+u32 int_mod_cq_depth_16;
+u32 int_mod_cq_depth_4;
+u32 int_mod_cq_depth_1;
+
+#include "nes_cm.h"
+
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+static unsigned char *nes_iwarp_state_str[] = {
+       "Non-Existant",
+       "Idle",
+       "RTS",
+       "Closing",
+       "RSVD1",
+       "Terminate",
+       "Error",
+       "RSVD2",
+};
+
+static unsigned char *nes_tcp_state_str[] = {
+       "Non-Existant",
+       "Closed",
+       "Listen",
+       "SYN Sent",
+       "SYN Rcvd",
+       "Established",
+       "Close Wait",
+       "FIN Wait 1",
+       "Closing",
+       "Last Ack",
+       "FIN Wait 2",
+       "Time Wait",
+       "RSVD1",
+       "RSVD2",
+       "RSVD3",
+       "RSVD4",
+};
+#endif
+
+
+/**
+ * nes_nic_init_timer_defaults
+ */
+void  nes_nic_init_timer_defaults(struct nes_device *nesdev, u8 jumbomode)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       shared_timer->timer_in_use_min = NES_NIC_FAST_TIMER_LOW;
+       shared_timer->timer_in_use_max = NES_NIC_FAST_TIMER_HIGH;
+       if (jumbomode) {
+               shared_timer->threshold_low    = DEFAULT_JUMBO_NES_QL_LOW;
+               shared_timer->threshold_target = DEFAULT_JUMBO_NES_QL_TARGET;
+               shared_timer->threshold_high   = DEFAULT_JUMBO_NES_QL_HIGH;
+       } else {
+               shared_timer->threshold_low    = DEFAULT_NES_QL_LOW;
+               shared_timer->threshold_target = DEFAULT_NES_QL_TARGET;
+               shared_timer->threshold_high   = DEFAULT_NES_QL_HIGH;
+       }
+
+       /* todo use netdev->mtu to set thresholds */
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_init_timer
+ */
+static void  nes_nic_init_timer(struct nes_device *nesdev)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       if (shared_timer->timer_in_use_old == 0) {
+               nesdev->deepcq_count = 0;
+               shared_timer->timer_direction_upward = 0;
+               shared_timer->timer_direction_downward = 0;
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER;
+               shared_timer->timer_in_use_old = 0;
+
+       }
+       if (shared_timer->timer_in_use != shared_timer->timer_in_use_old) {
+               shared_timer->timer_in_use_old = shared_timer->timer_in_use;
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+                       0x80000000 | ((u32)(shared_timer->timer_in_use*8)));
+       }
+       /* todo use netdev->mtu to set thresholds */
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_tune_timer
+ */
+static void nes_nic_tune_timer(struct nes_device *nesdev)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+       u16 cq_count = nesdev->currcq_count;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       if (shared_timer->cq_count_old < cq_count) {
+               if (cq_count > shared_timer->threshold_low)
+                       shared_timer->cq_direction_downward=0;
+       }
+       if (shared_timer->cq_count_old >= cq_count)
+               shared_timer->cq_direction_downward++;
+       shared_timer->cq_count_old = cq_count;
+       if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
+               if (cq_count <= shared_timer->threshold_low) {
+                       shared_timer->threshold_low = shared_timer->threshold_low/2;
+                       shared_timer->cq_direction_downward=0;
+                       nesdev->currcq_count = 0;
+                       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+                       return;
+               }
+       }
+
+       if (cq_count > 1) {
+               nesdev->deepcq_count += cq_count;
+               if (cq_count <= shared_timer->threshold_low) {       /* increase timer gently */
+                       shared_timer->timer_direction_upward++;
+                       shared_timer->timer_direction_downward = 0;
+               } else if (cq_count <= shared_timer->threshold_target) { /* balanced */
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward = 0;
+               } else if (cq_count <= shared_timer->threshold_high) {  /* decrease timer gently */
+                       shared_timer->timer_direction_downward++;
+                       shared_timer->timer_direction_upward = 0;
+               } else if (cq_count <= (shared_timer->threshold_high) * 2) {
+                       shared_timer->timer_in_use -= 2;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward++;
+               } else {
+                       shared_timer->timer_in_use -= 4;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward++;
+               }
+
+               if (shared_timer->timer_direction_upward > 3 ) {  /* using history */
+                       shared_timer->timer_in_use += 3;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward = 0;
+               }
+               if (shared_timer->timer_direction_downward > 5) { /* using history */
+                       shared_timer->timer_in_use -= 4 ;
+                       shared_timer->timer_direction_downward = 0;
+                       shared_timer->timer_direction_upward = 0;
+               }
+       }
+
+       /* boundary checking */
+       if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
+       else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
+       }
+
+       nesdev->currcq_count = 0;
+
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_init_adapter - initialize adapter
+ */
+struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
+       struct nes_adapter *nesadapter = NULL;
+       unsigned long num_pds;
+       u32 u32temp;
+       u32 port_count;
+       u16 max_rq_wrs;
+       u16 max_sq_wrs;
+       u32 max_mr;
+       u32 max_256pbl;
+       u32 max_4kpbl;
+       u32 max_qp;
+       u32 max_irrq;
+       u32 max_cq;
+       u32 hte_index_mask;
+       u32 adapter_size;
+       u32 arp_table_size;
+       u16 vendor_id;
+       u8  OneG_Mode;
+       u8  func_index;
+
+       /* search the list of existing adapters */
+       list_for_each_entry(nesadapter, &nes_adapter_list, list) {
+               nes_debug(NES_DBG_INIT, "Searching Adapter list for PCI devfn = 0x%X,"
+                               " adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
+                               nesdev->pcidev->devfn,
+                               PCI_SLOT(nesadapter->devfn),
+                               nesadapter->bus_number,
+                               PCI_SLOT(nesdev->pcidev->devfn),
+                               nesdev->pcidev->bus->number );
+               if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
+                               (nesadapter->bus_number == nesdev->pcidev->bus->number)) {
+                       nesadapter->ref_count++;
+                       return nesadapter;
+               }
+       }
+
+       /* no adapter found */
+       num_pds = pci_resource_len(nesdev->pcidev, BAR_1) >> PAGE_SHIFT;
+       if ((hw_rev != NE020_REV) && (hw_rev != NE020_REV1)) {
+               nes_debug(NES_DBG_INIT, "NE020 driver detected unknown hardware revision 0x%x\n",
+                               hw_rev);
+               return NULL;
+       }
+
+       nes_debug(NES_DBG_INIT, "Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
+                       nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 4),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 8));
+
+       nes_debug(NES_DBG_INIT, "Reset and init NE020\n");
+
+
+       if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
+               return NULL;
+       if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
+               return NULL;
+       nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+       max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
+       nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
+       if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
+               nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to hash table size = 0x%08X\n",
+                               max_qp, u32temp);
+               max_qp = (u32)1 << (u32temp & 0x001f);
+       }
+
+       hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
+       nes_debug(NES_DBG_INIT, "Max QP = %u, hte_index_mask = 0x%08X.\n",
+                       max_qp, hte_index_mask);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
+
+       max_irrq = 1 << (u32temp & 0x001f);
+
+       if (max_qp > max_irrq) {
+               max_qp = max_irrq;
+               nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to Available Q1s.\n",
+                               max_qp);
+       }
+
+       /* there should be no reason to allocate more pds than qps */
+       if (num_pds > max_qp)
+               num_pds = max_qp;
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
+       max_mr = (u32)8192 << (u32temp & 0x7);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
+       max_256pbl = (u32)1 << (u32temp & 0x0000001f);
+       max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
+       max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
+       arp_table_size = 1 << u32temp;
+
+       adapter_size = (sizeof(struct nes_adapter) +
+                       (sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
+       adapter_size += sizeof(struct nes_qp **) * max_qp;
+
+       /* allocate a new adapter struct */
+       nesadapter = kzalloc(adapter_size, GFP_KERNEL);
+       if (nesadapter == NULL) {
+               return NULL;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
+                       nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
+
+       /* populate the new nesadapter */
+       nesadapter->devfn = nesdev->pcidev->devfn;
+       nesadapter->bus_number = nesdev->pcidev->bus->number;
+       nesadapter->ref_count = 1;
+       nesadapter->timer_int_req = 0xffff0000;
+       nesadapter->OneG_Mode = OneG_Mode;
+       nesadapter->doorbell_start = nesdev->doorbell_region;
+
+       /* nesadapter->tick_delta = clk_divisor; */
+       nesadapter->hw_rev = hw_rev;
+       nesadapter->port_count = port_count;
+
+       nesadapter->max_qp = max_qp;
+       nesadapter->hte_index_mask = hte_index_mask;
+       nesadapter->max_irrq = max_irrq;
+       nesadapter->max_mr = max_mr;
+       nesadapter->max_256pbl = max_256pbl - 1;
+       nesadapter->max_4kpbl = max_4kpbl - 1;
+       nesadapter->max_cq = max_cq;
+       nesadapter->free_256pbl = max_256pbl - 1;
+       nesadapter->free_4kpbl = max_4kpbl - 1;
+       nesadapter->max_pd = num_pds;
+       nesadapter->arp_table_size = arp_table_size;
+
+       nesadapter->et_pkt_rate_low = NES_TIMER_ENABLE_LIMIT;
+       if (nes_drv_opt & NES_DRV_OPT_DISABLE_INT_MOD) {
+               nesadapter->et_use_adaptive_rx_coalesce = 0;
+               nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+               nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+       } else {
+               nesadapter->et_use_adaptive_rx_coalesce = 1;
+               nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+               nesadapter->et_rx_coalesce_usecs_irq = 0;
+               printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __FUNCTION__);
+       }
+       /* Setup and enable the periodic timer */
+       if (nesadapter->et_rx_coalesce_usecs_irq)
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
+                               ((u32)(nesadapter->et_rx_coalesce_usecs_irq * 8)));
+       else
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
+
+       nesadapter->base_pd = 1;
+
+       nesadapter->device_cap_flags =
+                       IB_DEVICE_ZERO_STAG | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW;
+
+       nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
+                       [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
+       nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
+       nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
+       nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
+       nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
+       nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
+
+
+       /* mark the usual suspect QPs and CQs as in use */
+       for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
+               set_bit(u32temp, nesadapter->allocated_qps);
+               set_bit(u32temp, nesadapter->allocated_cqs);
+       }
+
+       for (u32temp = 0; u32temp < 20; u32temp++)
+               set_bit(u32temp, nesadapter->allocated_pds);
+       u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
+
+       max_rq_wrs = ((u32temp >> 8) & 3);
+       switch (max_rq_wrs) {
+               case 0:
+                       max_rq_wrs = 4;
+                       break;
+               case 1:
+                       max_rq_wrs = 16;
+                       break;
+               case 2:
+                       max_rq_wrs = 32;
+                       break;
+               case 3:
+                       max_rq_wrs = 512;
+                       break;
+       }
+
+       max_sq_wrs = (u32temp & 3);
+       switch (max_sq_wrs) {
+               case 0:
+                       max_sq_wrs = 4;
+                       break;
+               case 1:
+                       max_sq_wrs = 16;
+                       break;
+               case 2:
+                       max_sq_wrs = 32;
+                       break;
+               case 3:
+                       max_sq_wrs = 512;
+                       break;
+       }
+       nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
+       nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
+
+       nesadapter->max_sge = 4;
+       nesadapter->max_cqe = 32767;
+
+       if (nes_read_eeprom_values(nesdev, nesadapter)) {
+               printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+               kfree(nesadapter);
+               return NULL;
+       }
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
+       nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
+                       (u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
+
+       /* setup port configuration */
+       if (nesadapter->port_count == 1) {
+               u32temp = 0x00000000;
+               if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
+                       nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
+               else
+                       nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+       } else {
+               if (nesadapter->port_count == 2)
+                       u32temp = 0x00000044;
+               else
+                       u32temp = 0x000000e4;
+               nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+       }
+
+       nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+       nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
+                       nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
+
+       spin_lock_init(&nesadapter->resource_lock);
+       spin_lock_init(&nesadapter->phy_lock);
+       spin_lock_init(&nesadapter->pbl_lock);
+       spin_lock_init(&nesadapter->periodic_timer_lock);
+
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
+
+       if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+               u32 pcs_control_status0, pcs_control_status1;
+               u32 reset_value;
+               u32 i = 0;
+               u32 int_cnt = 0;
+               u32 ext_cnt = 0;
+               unsigned long flags;
+               u32 j = 0;
+
+               pcs_control_status0 = nes_read_indexed(nesdev,
+                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+               pcs_control_status1 = nes_read_indexed(nesdev,
+                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+               for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+                       pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                       if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+                           || (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
+                               int_cnt++;
+                       msleep(1);
+               }
+               if (int_cnt > 1) {
+                       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       mh_detected++;
+                       reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+                       reset_value |= 0x0000003d;
+                       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                               & 0x00000040) != 0x00000040) && (j++ < 5000));
+                       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+                       pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+                       for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+                               pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                               pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                               if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+                                       || (0x0F000100 == (pcs_control_status1 & 0x0F000100))) {
+                                       if (++ext_cnt > int_cnt) {
+                                               spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
+                                                               0x0000F0C8);
+                                               mh_detected++;
+                                               reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+                                               reset_value |= 0x0000003d;
+                                               nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                                               while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                                                       & 0x00000040) != 0x00000040) && (j++ < 5000));
+                                               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+                                               break;
+                                       }
+                               }
+                               msleep(1);
+                       }
+               }
+       }
+
+       if (nesadapter->hw_rev == NE020_REV) {
+               init_timer(&nesadapter->mh_timer);
+               nesadapter->mh_timer.function = nes_mh_fix;
+               nesadapter->mh_timer.expires = jiffies + (HZ/5);  /* 1 second */
+               nesadapter->mh_timer.data = (unsigned long)nesdev;
+               add_timer(&nesadapter->mh_timer);
+       } else {
+               nes_write32(nesdev->regs+NES_INTF_INT_STAT, 0x0f000000);
+       }
+
+       init_timer(&nesadapter->lc_timer);
+       nesadapter->lc_timer.function = nes_clc;
+       nesadapter->lc_timer.expires = jiffies + 3600 * HZ;  /* 1 hour */
+       nesadapter->lc_timer.data = (unsigned long)nesdev;
+       add_timer(&nesadapter->lc_timer);
+
+       list_add_tail(&nesadapter->list, &nes_adapter_list);
+
+       for (func_index = 0; func_index < 8; func_index++) {
+               pci_bus_read_config_word(nesdev->pcidev->bus,
+                                       PCI_DEVFN(PCI_SLOT(nesdev->pcidev->devfn),
+                                       func_index), 0, &vendor_id);
+               if (vendor_id == 0xffff)
+                       break;
+       }
+       nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __FUNCTION__,
+               func_index, pci_name(nesdev->pcidev));
+       nesadapter->adapter_fcn_count = func_index;
+
+       return nesadapter;
+}
+
+
+/**
+ * nes_reset_adapter_ne020
+ */
+unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
+{
+       u32 port_count;
+       u32 u32temp;
+       u32 i;
+
+       u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+       port_count = ((u32temp & 0x00000300) >> 8) + 1;
+       /* TODO: assuming that both SERDES are set the same for now */
+       *OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
+       nes_debug(NES_DBG_INIT, "Initial Software Reset = 0x%08X, port_count=%u\n",
+                       u32temp, port_count);
+       if (*OneG_Mode)
+               nes_debug(NES_DBG_INIT, "Running in 1G mode.\n");
+       u32temp &= 0xff00ffc0;
+       switch (port_count) {
+               case 1:
+                       u32temp |= 0x00ee0000;
+                       break;
+               case 2:
+                       u32temp |= 0x00cc0000;
+                       break;
+               case 4:
+                       u32temp |= 0x00000000;
+                       break;
+               default:
+                       return 0;
+                       break;
+       }
+
+       /* check and do full reset if needed */
+       if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
+               nes_debug(NES_DBG_INIT, "Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
+               nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+               i = 0;
+               while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+                       mdelay(1);
+               if (i >= 10000) {
+                       nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
+                       return 0;
+               }
+       }
+
+       /* port reset */
+       switch (port_count) {
+               case 1:
+                       u32temp |= 0x00ee0010;
+                       break;
+               case 2:
+                       u32temp |= 0x00cc0030;
+                       break;
+               case 4:
+                       u32temp |= 0x00000030;
+                       break;
+       }
+
+       nes_debug(NES_DBG_INIT, "Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
+       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+       i = 0;
+       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+               mdelay(1);
+       if (i >= 10000) {
+               nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
+               return 0;
+       }
+
+       /* serdes 0 */
+       i = 0;
+       while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+                       & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+               mdelay(1);
+       if (i >= 5000) {
+               nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
+               return 0;
+       }
+
+       /* serdes 1 */
+       if (port_count > 1) {
+               i = 0;
+               while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+                               & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+                       mdelay(1);
+               if (i >= 5000) {
+                       nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
+                       return 0;
+               }
+       }
+
+
+
+       i = 0;
+       while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
+               mdelay(1);
+       if (i >= 10000) {
+               printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+                               nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+               return 0;
+       }
+
+       return port_count;
+}
+
+
+/**
+ * nes_init_serdes
+ */
+int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8  OneG_Mode)
+{
+       int i;
+       u32 u32temp;
+
+       if (hw_rev != NE020_REV) {
+               /* init serdes 0 */
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+               if (!OneG_Mode)
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
+               if (port_count > 1) {
+                       /* init serdes 1 */
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
+                       if (!OneG_Mode)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
+                       }
+       } else {
+               /* init serdes 0 */
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+               i = 0;
+               while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+                               & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+                       mdelay(1);
+               if (i >= 5000) {
+                       nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
+                       return 1;
+               }
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+               if (OneG_Mode)
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
+               else
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+               if (port_count > 1) {
+                       /* init serdes 1 */
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
+                       i = 0;
+                       while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+                               & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
+                               mdelay(1);
+                       if (i >= 5000) {
+                               printk("%s: Init: serdes 1 not ready, status=%x\n", __FUNCTION__, u32temp);
+                               /* return 1; */
+                       }
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
+               }
+       }
+       return 0;
+}
+
+
+/**
+ * nes_init_csr_ne020
+ * Initialize registers for ne020 hardware
+ */
+void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
+{
+       u32 u32temp;
+
+       nes_debug(NES_DBG_INIT, "port_count=%d\n", port_count);
+
+       nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
+       /* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
+       nes_write_indexed(nesdev, 0x000001E8, 0x00020874);
+       nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
+       /* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
+       nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
+       nes_write_indexed(nesdev, 0x00000600, 0x55555555);
+       nes_write_indexed(nesdev, 0x00000604, 0x55555555);
+
+       /* TODO: move these MAC register settings to NIC bringup */
+       nes_write_indexed(nesdev, 0x00002000, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002004, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
+       nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
+       nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
+       if (port_count > 1) {
+               nes_write_indexed(nesdev, 0x00002200, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002204, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000908, 0x20000001);
+       }
+       if (port_count > 2) {
+               nes_write_indexed(nesdev, 0x00002400, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002404, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000910, 0x20000001);
+
+               nes_write_indexed(nesdev, 0x00002600, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002604, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000918, 0x20000001);
+       }
+
+       nes_write_indexed(nesdev, 0x00005000, 0x00018000);
+       /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
+       nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+       nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
+
+       /* TODO: move this to code, get from EEPROM */
+       nes_write_indexed(nesdev, 0x00000900, 0x20000001);
+       nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
+       nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
+                                                                                                               //
+       nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
+       /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
+
+       if (hw_rev != NE020_REV) {
+               u32temp = nes_read_indexed(nesdev, 0x000008e8);
+               u32temp |= 0x80000000;
+               nes_write_indexed(nesdev, 0x000008e8, u32temp);
+               u32temp = nes_read_indexed(nesdev, 0x000021f8);
+               u32temp &= 0x7fffffff;
+               u32temp |= 0x7fff0010;
+               nes_write_indexed(nesdev, 0x000021f8, u32temp);
+       }
+}
+
+
+/**
+ * nes_destroy_adapter - destroy the adapter structure
+ */
+void nes_destroy_adapter(struct nes_adapter *nesadapter)
+{
+       struct nes_adapter *tmp_adapter;
+
+       list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
+               nes_debug(NES_DBG_SHUTDOWN, "Nes Adapter list entry = 0x%p.\n",
+                               tmp_adapter);
+       }
+
+       nesadapter->ref_count--;
+       if (!nesadapter->ref_count) {
+               if (nesadapter->hw_rev == NE020_REV) {
+                       del_timer(&nesadapter->mh_timer);
+               }
+               del_timer(&nesadapter->lc_timer);
+
+               list_del(&nesadapter->list);
+               kfree(nesadapter);
+       }
+}
+
+
+/**
+ * nes_init_cqp
+ */
+int nes_init_cqp(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_cqp_qp_context *cqp_qp_context;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_ceq *ceq;
+       struct nes_hw_ceq *nic_ceq;
+       struct nes_hw_aeq *aeq;
+       void *vmem;
+       dma_addr_t pmem;
+       u32 count=0;
+       u32 cqp_head;
+       u64 u64temp;
+       u32 u32temp;
+
+       /* allocate CQP memory */
+       /* Need to add max_cq to the aeq size once cq overflow checking is added back */
+       /* SQ is 512 byte aligned, others are 256 byte aligned */
+       nesdev->cqp_mem_size = 512 +
+                       (sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
+                       (sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
+                       max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
+                       max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
+                       (sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
+                       sizeof(struct nes_hw_cqp_qp_context);
+
+       nesdev->cqp_vbase = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                       &nesdev->cqp_pbase);
+       if (!nesdev->cqp_vbase) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory for host descriptor rings\n");
+               return -ENOMEM;
+       }
+       memset(nesdev->cqp_vbase, 0, nesdev->cqp_mem_size);
+
+       /* Allocate a twice the number of CQP requests as the SQ size */
+       nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) *
+                       2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
+       if (nesdev->nes_cqp_requests == NULL) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory CQP request entries.\n");
+               pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+                               nesdev->cqp.sq_pbase);
+               return -ENOMEM;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
+                       nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
+
+       spin_lock_init(&nesdev->cqp.lock);
+       init_waitqueue_head(&nesdev->cqp.waitq);
+
+       /* Setup Various Structures */
+       vmem = (void *)(((unsigned long)nesdev->cqp_vbase + (512 - 1)) &
+                       ~(unsigned long)(512 - 1));
+       pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
+                       ~(unsigned long long)(512 - 1));
+
+       nesdev->cqp.sq_vbase = vmem;
+       nesdev->cqp.sq_pbase = pmem;
+       nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
+       nesdev->cqp.sq_head = 0;
+       nesdev->cqp.sq_tail = 0;
+       nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
+
+       vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+       pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+
+       nesdev->ccq.cq_vbase = vmem;
+       nesdev->ccq.cq_pbase = pmem;
+       nesdev->ccq.cq_size = NES_CCQ_SIZE;
+       nesdev->ccq.cq_head = 0;
+       nesdev->ccq.ce_handler = nes_cqp_ce_handler;
+       nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
+
+       vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+       pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+
+       nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
+       ceq = &nesadapter->ceq[nesdev->ceq_index];
+       ceq->ceq_vbase = vmem;
+       ceq->ceq_pbase = pmem;
+       ceq->ceq_size = NES_CCEQ_SIZE;
+       ceq->ceq_head = 0;
+
+       vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+       pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+
+       nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
+       nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
+       nic_ceq->ceq_vbase = vmem;
+       nic_ceq->ceq_pbase = pmem;
+       nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
+       nic_ceq->ceq_head = 0;
+
+       vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+       pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+
+       aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
+       aeq->aeq_vbase = vmem;
+       aeq->aeq_pbase = pmem;
+       aeq->aeq_size = nesadapter->max_qp;
+       aeq->aeq_head = 0;
+
+       /* Setup QP Context */
+       vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+       pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+
+       cqp_qp_context = vmem;
+       cqp_qp_context->context_words[0] =
+                       cpu_to_le32((PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10));
+       cqp_qp_context->context_words[1] = 0;
+       cqp_qp_context->context_words[2] = cpu_to_le32((u32)nesdev->cqp.sq_pbase);
+       cqp_qp_context->context_words[3] = cpu_to_le32(((u64)nesdev->cqp.sq_pbase) >> 32);
+
+
+       /* Write the address to Create CQP */
+       if ((sizeof(dma_addr_t) > 4)) {
+               nes_write_indexed(nesdev,
+                               NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                               ((u64)pmem) >> 32);
+       } else {
+               nes_write_indexed(nesdev,
+                               NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
+       }
+       nes_write_indexed(nesdev,
+                       NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                       (u32)pmem);
+
+       INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
+       INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
+
+       for (count = 0; count < 2*NES_CQP_SQ_SIZE; count++) {
+               init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
+               list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
+       }
+
+       /* Write Create CCQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+                       NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+                           (nesdev->ccq.cq_number |
+                            ((u32)nesdev->ceq_index << 16)));
+       u64temp = (u64)nesdev->ccq.cq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+       u64temp = (unsigned long)&nesdev->ccq;
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
+                       cpu_to_le32((u32)(u64temp >> 1));
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+                       cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+
+       /* Write Create CEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                           (NES_CQP_CREATE_CEQ + ((u32)nesdev->ceq_index << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, ceq->ceq_size);
+       u64temp = (u64)ceq->ceq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Write Create AEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_AEQ + ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX, aeq->aeq_size);
+       u64temp = (u64)aeq->aeq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Write Create NIC CEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_CEQ + ((u32)nesdev->nic_ceq_index << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, nic_ceq->ceq_size);
+       u64temp = (u64)nic_ceq->ceq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Poll until CCQP done */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Error creating CQP\n");
+                       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                                       nesdev->cqp_vbase, nesdev->cqp_pbase);
+                       return -1;
+               }
+               udelay(10);
+       } while (!(nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
+
+       nes_debug(NES_DBG_INIT, "CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       u32temp = 0x04800000;
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
+
+       /* wait for the CCQ, CEQ, and AEQ to get created */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
+                       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                                       nesdev->cqp_vbase, nesdev->cqp_pbase);
+                       return -1;
+               }
+               udelay(10);
+       } while (((nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
+
+       /* dump the QP status value */
+       nes_debug(NES_DBG_INIT, "QP Status = 0x%08X\n", nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       nesdev->cqp.sq_tail++;
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_cqp
+ */
+int nes_destroy_cqp(struct nes_device *nesdev)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       u32 count = 0;
+       u32 cqp_head;
+       unsigned long flags;
+
+       do {
+               if (count++ > 1000)
+                       break;
+               udelay(10);
+       } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
+
+       /* Reset CCQ */
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
+                       nesdev->ccq.cq_number);
+
+       /* Disable device interrupts */
+       nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+       /* Destroy the AEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
+                       ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+
+       /* Destroy the NIC CEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+                       ((u32)nesdev->nic_ceq_index << 8));
+
+       /* Destroy the CEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+                       (nesdev->ceq_index << 8));
+
+       /* Destroy the CCQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
+                       ((u32)nesdev->ceq_index << 16));
+
+       /* Destroy CQP */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
+                       NES_CQP_QP_TYPE_CQP);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
+
+       barrier();
+       /* Ring doorbell (5 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+       /* wait for the CCQ, CEQ, and AEQ to get destroyed */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
+                                       PCI_FUNC(nesdev->pcidev->devfn));
+                       break;
+               }
+               udelay(10);
+       } while (((nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15 << 8)) != 0));
+
+       /* dump the QP status value */
+       nes_debug(NES_DBG_SHUTDOWN, "Function%d: QP Status = 0x%08X\n",
+                       PCI_FUNC(nesdev->pcidev->devfn),
+                       nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       kfree(nesdev->nes_cqp_requests);
+
+       /* Free the control structures */
+       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+                       nesdev->cqp.sq_pbase);
+
+       return 0;
+}
+
+
+/**
+ * nes_init_phy
+ */
+int nes_init_phy(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 counter = 0;
+       u32 mac_index = nesdev->mac_index;
+       u32 tx_config;
+       u16 phy_data;
+
+       if (nesadapter->OneG_Mode) {
+               nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
+               if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
+                       printk(PFX "%s: Programming mdc config for 1G\n", __FUNCTION__);
+                       tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+                       tx_config |= 0x04;
+                       nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+               }
+
+               nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
+                               nesadapter->phy_index[mac_index], phy_data);
+               nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index],  0xb000);
+
+               /* Reset the PHY */
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
+               udelay(100);
+               counter = 0;
+               do {
+                       nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+                       if (counter++ > 100) break;
+               } while (phy_data & 0x8000);
+
+               /* Setting no phy loopback */
+               phy_data &= 0xbfff;
+               phy_data |= 0x1140;
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index],  phy_data);
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x17 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x1e = 0x%X.\n", phy_data);
+
+               /* Setting the interrupt mask */
+               nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+               nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee);
+
+               nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+
+               /* turning on flow control */
+               nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+               nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+                               (phy_data & ~(0x03E0)) | 0xc00);
+               /* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+                               phy_data | 0xc00); */
+               nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+               /* Clear Half duplex */
+               nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
+                               phy_data & ~(0x0100));
+               nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
+       } else {
+               if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+                       /* setup 10G MDIO operation */
+                       tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+                       tx_config |= 0x14;
+                       nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+               }
+       }
+       return 0;
+}
+
+
+/**
+ * nes_replenish_nic_rq
+ */
+static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
+{
+       unsigned long flags;
+       dma_addr_t bus_address;
+       struct sk_buff *skb;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       struct nes_hw_nic *nesnic;
+       struct nes_device *nesdev;
+       u32 rx_wqes_posted = 0;
+
+       nesnic = &nesvnic->nic;
+       nesdev = nesvnic->nesdev;
+       spin_lock_irqsave(&nesnic->rq_lock, flags);
+       if (nesnic->replenishing_rq !=0) {
+               if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+                               (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+                       atomic_set(&nesvnic->rx_skb_timer_running, 1);
+                       spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                       nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2);      /* 1/2 second */
+                       add_timer(&nesvnic->rq_wqes_timer);
+               } else
+               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+               return;
+       }
+       nesnic->replenishing_rq = 1;
+       spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+       do {
+               skb = dev_alloc_skb(nesvnic->max_frame_size);
+               if (skb) {
+                       skb->dev = nesvnic->netdev;
+
+                       bus_address = pci_map_single(nesdev->pcidev,
+                                       skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+                       nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
+                                       cpu_to_le32(nesvnic->max_frame_size);
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
+                                       cpu_to_le32((u32)bus_address);
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
+                                       cpu_to_le32((u32)((u64)bus_address >> 32));
+                       nesnic->rx_skb[nesnic->rq_head] = skb;
+                       nesnic->rq_head++;
+                       nesnic->rq_head &= nesnic->rq_size - 1;
+                       atomic_dec(&nesvnic->rx_skbs_needed);
+                       barrier();
+                       if (++rx_wqes_posted == 255) {
+                               nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+                               rx_wqes_posted = 0;
+                       }
+               } else {
+                       spin_lock_irqsave(&nesnic->rq_lock, flags);
+                       if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+                                       (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+                               atomic_set(&nesvnic->rx_skb_timer_running, 1);
+                               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                               nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2);      /* 1/2 second */
+                               add_timer(&nesvnic->rq_wqes_timer);
+                       } else
+                               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                       break;
+               }
+       } while (atomic_read(&nesvnic->rx_skbs_needed));
+       barrier();
+       if (rx_wqes_posted)
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+       nesnic->replenishing_rq = 0;
+}
+
+
+/**
+ * nes_rq_wqes_timeout
+ */
+static void nes_rq_wqes_timeout(unsigned long parm)
+{
+       struct nes_vnic *nesvnic = (struct nes_vnic *)parm;
+       printk("%s: Timer fired.\n", __FUNCTION__);
+       atomic_set(&nesvnic->rx_skb_timer_running, 0);
+       if (atomic_read(&nesvnic->rx_skbs_needed))
+               nes_replenish_nic_rq(nesvnic);
+}
+
+
+/**
+ * nes_init_nic_qp
+ */
+int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_nic_sq_wqe *nic_sqe;
+       struct nes_hw_nic_qp_context *nic_context;
+       struct sk_buff *skb;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       unsigned long flags;
+       void *vmem;
+       dma_addr_t pmem;
+       u64 u64temp;
+       int ret;
+       u32 cqp_head;
+       u32 counter;
+       u32 wqe_count;
+       u8 jumbomode=0;
+
+       /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
+       nesvnic->nic_mem_size = 256 +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
+                       (NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
+                       sizeof(struct nes_hw_nic_qp_context);
+
+       nesvnic->nic_vbase = pci_alloc_consistent(nesdev->pcidev, nesvnic->nic_mem_size,
+                       &nesvnic->nic_pbase);
+       if (!nesvnic->nic_vbase) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory for NIC host descriptor rings\n");
+               return -ENOMEM;
+       }
+       memset(nesvnic->nic_vbase, 0, nesvnic->nic_mem_size);
+       nes_debug(NES_DBG_INIT, "Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
+                       nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
+
+       vmem = (void *)(((unsigned long)nesvnic->nic_vbase + (256 - 1)) &
+                       ~(unsigned long)(256 - 1));
+       pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
+                       ~(unsigned long long)(256 - 1));
+
+       /* Setup the first Fragment buffers */
+       nesvnic->nic.first_frag_vbase = vmem;
+
+       for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+               nesvnic->nic.frag_paddr[counter] = pmem;
+               pmem += sizeof(struct nes_first_frag);
+       }
+
+       /* setup the SQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
+
+       nesvnic->nic.sq_vbase = (void *)vmem;
+       nesvnic->nic.sq_pbase = pmem;
+       nesvnic->nic.sq_head = 0;
+       nesvnic->nic.sq_tail = 0;
+       nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
+       for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+               nic_sqe = &nesvnic->nic.sq_vbase[counter];
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
+                               cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM |
+                               NES_NIC_SQ_WQE_COMPLETION);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
+                               cpu_to_le32((u32)NES_FIRST_FRAG_SIZE << 16);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
+                               cpu_to_le32((u32)nesvnic->nic.frag_paddr[counter]);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
+                               cpu_to_le32((u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32));
+       }
+
+       nesvnic->get_cqp_request = nes_get_cqp_request;
+       nesvnic->post_cqp_request = nes_post_cqp_request;
+       nesvnic->mcrq_mcast_filter = NULL;
+
+       spin_lock_init(&nesvnic->nic.sq_lock);
+       spin_lock_init(&nesvnic->nic.rq_lock);
+
+       /* setup the RQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+       pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+
+
+       nesvnic->nic.rq_vbase = vmem;
+       nesvnic->nic.rq_pbase = pmem;
+       nesvnic->nic.rq_head = 0;
+       nesvnic->nic.rq_tail = 0;
+       nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
+
+       /* setup the CQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+       pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+
+       if (nesdev->nesadapter->netdev_count > 2)
+               nesvnic->mcrq_qp_id = nesvnic->nic_index + 32;
+       else
+               nesvnic->mcrq_qp_id = nesvnic->nic.qp_id + 4;
+
+       nesvnic->nic_cq.cq_vbase = vmem;
+       nesvnic->nic_cq.cq_pbase = pmem;
+       nesvnic->nic_cq.cq_head = 0;
+       nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
+
+       nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
+
+       /* Send CreateCQ request to CQP */
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+       cqp_head = nesdev->cqp.sq_head;
+
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
+                       NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+                       ((u32)nesvnic->nic_cq.cq_size << 16));
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
+                       nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16));
+       u64temp = (u64)nesvnic->nic_cq.cq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =  0;
+       u64temp = (unsigned long)&nesvnic->nic_cq;
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =  cpu_to_le32((u32)(u64temp >> 1));
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+                       cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       /* Send CreateQP request to CQP */
+       nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
+       nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
+                       cpu_to_le32((u32)NES_NIC_CTX_SIZE |
+                       ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
+       nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
+                       nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
+                       nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
+       if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) {
+               nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
+       }
+
+       u64temp = (u64)nesvnic->nic.sq_pbase;
+       nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+       nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+       u64temp = (u64)nesvnic->nic.rq_pbase;
+       nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+       nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
+                       NES_CQP_QP_TYPE_NIC);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
+       u64temp = (u64)nesvnic->nic_cq.cq_pbase +
+                       (nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+       nesdev->cqp.sq_head = cqp_head;
+
+       barrier();
+
+       /* Ring doorbell (2 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+       nes_debug(NES_DBG_INIT, "Waiting for create NIC QP%u to complete.\n",
+                       nesvnic->nic.qp_id);
+
+       ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_INIT, "Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
+                       nesvnic->nic.qp_id, ret);
+       if (!ret) {
+               nes_debug(NES_DBG_INIT, "NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
+               pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+                               nesvnic->nic_pbase);
+               return -EIO;
+       }
+
+       /* Populate the RQ */
+       for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
+               skb = dev_alloc_skb(nesvnic->max_frame_size);
+               if (!skb) {
+                       nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
+
+                       nes_destroy_nic_qp(nesvnic);
+                       return -ENOMEM;
+               }
+
+               skb->dev = netdev;
+
+               pmem = pci_map_single(nesdev->pcidev, skb->data,
+                               nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+               nic_rqe = &nesvnic->nic.rq_vbase[counter];
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
+               nesvnic->nic.rx_skb[counter] = skb;
+       }
+
+       wqe_count = NES_NIC_WQ_SIZE - 1;
+       nesvnic->nic.rq_head = wqe_count;
+       barrier();
+       do {
+               counter = min(wqe_count, ((u32)255));
+               wqe_count -= counter;
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
+       } while (wqe_count);
+       init_timer(&nesvnic->rq_wqes_timer);
+       nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
+       nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
+       nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
+
+       if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
+       {
+               nes_nic_init_timer(nesdev);
+               if (netdev->mtu > 1500)
+                       jumbomode = 1;
+                nes_nic_init_timer_defaults(nesdev, jumbomode);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_nic_qp
+ */
+void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
+{
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       u64 wqe_frag;
+       u32 cqp_head;
+       unsigned long flags;
+       int ret;
+
+       /* Free remaining NIC receive buffers */
+       while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
+               nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+               wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+               wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+               pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
+                               nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
+               nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
+       }
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+       /* Destroy NIC QP */
+       cqp_head = nesdev->cqp.sq_head;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+               (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+               nesvnic->nic.qp_id);
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+       /* Destroy NIC CQ */
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+               (NES_CQP_DESTROY_CQ | ((u32)nesvnic->nic_cq.cq_size << 16)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+               (nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16)));
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+
+       nesdev->cqp.sq_head = cqp_head;
+       barrier();
+
+       /* Ring doorbell (2 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+       nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
+                       " cqp.sq_tail=%u, cqp.sq_size=%u\n",
+                       cqp_head, nesdev->cqp.sq_head,
+                       nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
+
+       ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+                       NES_EVENT_TIMEOUT);
+
+       nes_debug(NES_DBG_SHUTDOWN, "Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
+                       " cqp.sq_head=%u, cqp.sq_tail=%u\n",
+                       ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+       if (!ret) {
+               nes_debug(NES_DBG_SHUTDOWN, "NIC QP%u destroy timeout expired\n",
+                               nesvnic->nic.qp_id);
+       }
+
+       pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+                       nesvnic->nic_pbase);
+}
+
+/**
+ * nes_napi_isr
+ */
+int nes_napi_isr(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 int_stat;
+
+       if (nesdev->napi_isr_ran) {
+               /* interrupt status has already been read in ISR */
+               int_stat = nesdev->int_stat;
+       } else {
+               int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+               nesdev->int_stat = int_stat;
+               nesdev->napi_isr_ran = 1;
+       }
+
+       int_stat &= nesdev->int_req;
+       /* iff NIC, process here, else wait for DPC */
+       if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
+               nesdev->napi_isr_ran = 0;
+               nes_write32(nesdev->regs+NES_INT_STAT,
+                               (int_stat &
+                               ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+
+               /* Process the CEQs */
+               nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
+
+               if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
+                                          (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+                                         ((nesadapter->et_use_adaptive_rx_coalesce) &&
+                                          (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
+                       if ((nesdev->int_req & NES_INT_TIMER) == 0) {
+                               /* Enable Periodic timer interrupts */
+                               nesdev->int_req |= NES_INT_TIMER;
+                               /* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
+                               /* TODO: need to also ack other unused periodic timer values, get from nesadapter */
+                               nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                               nesdev->timer_int_req  | ~(nesdev->nesadapter->timer_int_req));
+                               nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+                                               ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+                       }
+
+                       if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+                       {
+                               nes_nic_init_timer(nesdev);
+                       }
+                       /* Enable interrupts, except CEQs */
+                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+               } else {
+                       /* Enable interrupts, make sure timer is off */
+                       nesdev->int_req &= ~NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+                       nesadapter->tune_timer.timer_in_use_old = 0;
+               }
+               nesdev->deepcq_count = 0;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+
+/**
+ * nes_dpc
+ */
+void nes_dpc(unsigned long param)
+{
+       struct nes_device *nesdev = (struct nes_device *)param;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 counter;
+       u32 loop_counter = 0;
+       u32 int_status_bit;
+       u32 int_stat;
+       u32 timer_stat;
+       u32 temp_int_stat;
+       u32 intf_int_stat;
+       u32 debug_error;
+       u32 processed_intf_int = 0;
+       u16 processed_timer_int = 0;
+       u16 completion_ints = 0;
+       u16 timer_ints = 0;
+
+       /* nes_debug(NES_DBG_ISR, "\n"); */
+
+       do {
+               timer_stat = 0;
+               if (nesdev->napi_isr_ran) {
+                       nesdev->napi_isr_ran = 0;
+                       int_stat = nesdev->int_stat;
+               } else
+                       int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
+               if (processed_intf_int != 0)
+                       int_stat &= nesdev->int_req & ~NES_INT_INTF;
+               else
+                       int_stat &= nesdev->int_req;
+               if (processed_timer_int == 0) {
+                       processed_timer_int = 1;
+                       if (int_stat & NES_INT_TIMER) {
+                               timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+                               if ((timer_stat & nesdev->timer_int_req) == 0) {
+                                       int_stat &= ~NES_INT_TIMER;
+                               }
+                       }
+               } else {
+                       int_stat &= ~NES_INT_TIMER;
+               }
+
+               if (int_stat) {
+                       if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                                       NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+                               /* Ack the interrupts */
+                               nes_write32(nesdev->regs+NES_INT_STAT,
+                                               (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                                               NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+                       }
+
+                       temp_int_stat = int_stat;
+                       for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
+                               if (int_stat & int_status_bit) {
+                                       nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
+                                       temp_int_stat &= ~int_status_bit;
+                                       completion_ints = 1;
+                               }
+                               if (!(temp_int_stat & 0x0000ffff))
+                                       break;
+                               int_status_bit <<= 1;
+                       }
+
+                       /* Process the AEQ for this pci function */
+                       int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
+                       if (int_stat & int_status_bit) {
+                               nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
+                       }
+
+                       /* Process the MAC interrupt for this pci function */
+                       int_status_bit = 1 << (24 + nesdev->mac_index);
+                       if (int_stat & int_status_bit) {
+                               nes_process_mac_intr(nesdev, nesdev->mac_index);
+                       }
+
+                       if (int_stat & NES_INT_TIMER) {
+                               if (timer_stat & nesdev->timer_int_req) {
+                                       nes_write32(nesdev->regs + NES_TIMER_STAT,
+                                                       (timer_stat & nesdev->timer_int_req) |
+                                                       ~(nesdev->nesadapter->timer_int_req));
+                                       timer_ints = 1;
+                               }
+                       }
+
+                       if (int_stat & NES_INT_INTF) {
+                               processed_intf_int = 1;
+                               intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+                               intf_int_stat &= nesdev->intf_int_req;
+                               if (NES_INTF_INT_CRITERR & intf_int_stat) {
+                                       debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+                                       printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+                                                       (u16)debug_error);
+                                       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+                                                       0x01010000 | (debug_error & 0x0000ffff));
+                                       /* BUG(); */
+                                       if (crit_err_count++ > 10)
+                                               nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+                               }
+                               if (NES_INTF_INT_PCIERR & intf_int_stat) {
+                                       printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
+                                       BUG();
+                               }
+                               if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
+                                       printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
+                                       BUG();
+                               }
+                               nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
+                       }
+
+                       if (int_stat & NES_INT_TSW) {
+                       }
+               }
+               /* Don't use the interface interrupt bit stay in loop */
+               int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                               NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+       } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
+
+       if (timer_ints == 1) {
+               if ((nesadapter->et_rx_coalesce_usecs_irq) || (nesadapter->et_use_adaptive_rx_coalesce)) {
+                       if (completion_ints == 0) {
+                               nesdev->timer_only_int_count++;
+                               if (nesdev->timer_only_int_count>=nesadapter->timer_int_limit) {
+                                       nesdev->timer_only_int_count = 0;
+                                       nesdev->int_req &= ~NES_INT_TIMER;
+                                       nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+                                       nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
+                               } else {
+                                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+                               }
+                       } else {
+                               if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+                               {
+                                       nes_nic_init_timer(nesdev);
+                               }
+                               nesdev->timer_only_int_count = 0;
+                               nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+                       }
+               } else {
+                       nesdev->timer_only_int_count = 0;
+                       nesdev->int_req &= ~NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                       nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                       nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+               }
+       } else {
+               if ( (completion_ints == 1) &&
+                        (((nesadapter->et_rx_coalesce_usecs_irq) &&
+                          (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+                         ((nesdev->deepcq_count > nesadapter->et_pkt_rate_low) &&
+                          (nesadapter->et_use_adaptive_rx_coalesce) )) ) {
+                       /* nes_debug(NES_DBG_ISR, "Enabling periodic timer interrupt.\n" ); */
+                       nesdev->timer_only_int_count = 0;
+                       nesdev->int_req |= NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                       nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+                                       ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+               } else {
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+               }
+       }
+       nesdev->deepcq_count = 0;
+}
+
+
+/**
+ * nes_process_ceq
+ */
+void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
+{
+       u64 u64temp;
+       struct nes_hw_cq *cq;
+       u32 head;
+       u32 ceq_size;
+
+       /* nes_debug(NES_DBG_CQ, "\n"); */
+       head = ceq->ceq_head;
+       ceq_size = ceq->ceq_size;
+
+       do {
+               if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
+                               NES_CEQE_VALID) {
+                       u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
+                                               ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
+                       u64temp <<= 1;
+                       cq = *((struct nes_hw_cq **)&u64temp);
+                       /* nes_debug(NES_DBG_CQ, "pCQ = %p\n", cq); */
+                       barrier();
+                       ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
+
+                       /* call the event handler */
+                       cq->ce_handler(nesdev, cq);
+
+                       if (++head >= ceq_size)
+                               head = 0;
+               } else {
+                       break;
+               }
+
+       } while (1);
+
+       ceq->ceq_head = head;
+}
+
+
+/**
+ * nes_process_aeq
+ */
+void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
+{
+//     u64 u64temp;
+       u32 head;
+       u32 aeq_size;
+       u32 aeqe_misc;
+       u32 aeqe_cq_id;
+       struct nes_hw_aeqe volatile *aeqe;
+
+       head = aeq->aeq_head;
+       aeq_size = aeq->aeq_size;
+
+       do {
+               aeqe = &aeq->aeq_vbase[head];
+               if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
+                       break;
+               aeqe_misc  = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+               aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+               if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
+                       if (aeqe_cq_id >= NES_FIRST_QPN) {
+                               /* dealing with an accelerated QP related AE */
+//                             u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
+//                                     ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+                               nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
+                       } else {
+                               /* TODO: dealing with a CQP related AE */
+                               nes_debug(NES_DBG_AEQ, "Processing CQP related AE, misc = 0x%04X\n",
+                                               (u16)(aeqe_misc >> 16));
+                       }
+               }
+
+               aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
+
+               if (++head >= aeq_size)
+                       head = 0;
+       }
+       while (1);
+       aeq->aeq_head = head;
+}
+
+static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 reset_value;
+       u32 i=0;
+       u32 u32temp;
+
+       if (nesadapter->hw_rev == NE020_REV) {
+               return;
+       }
+       mh_detected++;
+
+       reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+       if ((mac_index == 0) || ((mac_index == 1) && (nesadapter->OneG_Mode)))
+               reset_value |= 0x0000001d;
+       else
+               reset_value |= 0x0000002d;
+
+       if (4 <= (nesadapter->link_interrupt_count[mac_index] / ((u16)NES_MAX_LINK_INTERRUPTS))) {
+               if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+                       nesadapter->link_interrupt_count[0] = 0;
+                       nesadapter->link_interrupt_count[1] = 0;
+                       u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+                       if (0x00000040 & u32temp)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       else
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+                       reset_value |= 0x0000003d;
+               }
+               nesadapter->link_interrupt_count[mac_index] = 0;
+       }
+
+       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                       & 0x00000040) != 0x00000040) && (i++ < 5000));
+
+       if (0x0000003d == (reset_value & 0x0000003d)) {
+               u32 pcs_control_status0, pcs_control_status1;
+
+               for (i = 0; i < 10; i++) {
+                       pcs_control_status0 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                       if (((0x0F000000 == (pcs_control_status0 & 0x0F000000))
+                            && (pcs_control_status0 & 0x00100000))
+                           || ((0x0F000000 == (pcs_control_status1 & 0x0F000000))
+                               && (pcs_control_status1 & 0x00100000)))
+                               continue;
+                       else
+                               break;
+               }
+               if (10 == i) {
+                       u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+                       if (0x00000040 & u32temp)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       else
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+                       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                       while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET)
+                                & 0x00000040) != 0x00000040) && (i++ < 5000));
+               }
+       }
+}
+
+/**
+ * nes_process_mac_intr
+ */
+void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
+{
+       unsigned long flags;
+       u32 pcs_control_status;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_vnic *nesvnic;
+       u32 mac_status;
+       u32 mac_index = nesdev->mac_index;
+       u32 u32temp;
+       u16 phy_data;
+       u16 temp_phy_data;
+
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+       if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
+               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+               return;
+       }
+       nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+       /* ack the MAC interrupt */
+       mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
+       /* Clear the interrupt */
+       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
+
+       nes_debug(NES_DBG_PHY, "MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
+
+       if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
+               nesdev->link_status_interrupts++;
+               if (0 == (++nesadapter->link_interrupt_count[mac_index] % ((u16)NES_MAX_LINK_INTERRUPTS))) {
+                       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                       nes_reset_link(nesdev, mac_index);
+                       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+               }
+               /* read the PHY interrupt status register */
+               if (nesadapter->OneG_Mode) {
+                       do {
+                               nes_read_1G_phy_reg(nesdev, 0x1a,
+                                               nesadapter->phy_index[mac_index], &phy_data);
+                               nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1a = 0x%X.\n",
+                                               nesadapter->phy_index[mac_index], phy_data);
+                       } while (phy_data&0x8000);
+
+                       temp_phy_data = 0;
+                       do {
+                               nes_read_1G_phy_reg(nesdev, 0x11,
+                                               nesadapter->phy_index[mac_index], &phy_data);
+                               nes_debug(NES_DBG_PHY, "Phy%d data from register 0x11 = 0x%X.\n",
+                                               nesadapter->phy_index[mac_index], phy_data);
+                               if (temp_phy_data == phy_data)
+                                       break;
+                               temp_phy_data = phy_data;
+                       } while (1);
+
+                       nes_read_1G_phy_reg(nesdev, 0x1e,
+                                       nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1e = 0x%X.\n",
+                                       nesadapter->phy_index[mac_index], phy_data);
+
+                       nes_read_1G_phy_reg(nesdev, 1,
+                                       nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "1G phy%u data from register 1 = 0x%X\n",
+                                       nesadapter->phy_index[mac_index], phy_data);
+
+                       if (temp_phy_data & 0x1000) {
+                               nes_debug(NES_DBG_PHY, "The Link is up according to the PHY\n");
+                               phy_data = 4;
+                       } else {
+                               nes_debug(NES_DBG_PHY, "The Link is down according to the PHY\n");
+                       }
+               }
+               nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
+                               nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
+                               nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
+               pcs_control_status = nes_read_indexed(nesdev,
+                               NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+               pcs_control_status = nes_read_indexed(nesdev,
+                               NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+               nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
+                               mac_index, pcs_control_status);
+               if (nesadapter->OneG_Mode) {
+                       u32temp = 0x01010000;
+                       if (nesadapter->port_count > 2) {
+                               u32temp |= 0x02020000;
+                       }
+                       if ((pcs_control_status & u32temp)!= u32temp) {
+                               phy_data = 0;
+                               nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
+                       }
+               } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+                       nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+                       temp_phy_data = (u16)nes_read_indexed(nesdev,
+                                                               NES_IDX_MAC_MDIO_CONTROL);
+                       u32temp = 20;
+                       do {
+                               nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+                               phy_data = (u16)nes_read_indexed(nesdev,
+                                                               NES_IDX_MAC_MDIO_CONTROL);
+                               if ((phy_data == temp_phy_data) || (!(--u32temp)))
+                                       break;
+                               temp_phy_data = phy_data;
+                       } while (1);
+                       nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+                               __FUNCTION__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+
+               } else {
+                       phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+               }
+
+               if (phy_data & 0x0004) {
+                       nesadapter->mac_link_down[mac_index] = 0;
+                       list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+                               nes_debug(NES_DBG_PHY, "The Link is UP!!.  linkup was %d\n",
+                                               nesvnic->linkup);
+                               if (nesvnic->linkup == 0) {
+                                       printk(PFX "The Link is now up for port %u, netdev %p.\n",
+                                                       mac_index, nesvnic->netdev);
+                                       if (netif_queue_stopped(nesvnic->netdev))
+                                               netif_start_queue(nesvnic->netdev);
+                                       nesvnic->linkup = 1;
+                                       netif_carrier_on(nesvnic->netdev);
+                               }
+                       }
+               } else {
+                       nesadapter->mac_link_down[mac_index] = 1;
+                       list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+     &nb