diff options
Diffstat (limited to 'drivers/infiniband/hw/nes')
| -rw-r--r-- | drivers/infiniband/hw/nes/Makefile | 2 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes.c | 97 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes.h | 45 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.c | 1627 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.h | 90 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_context.h | 2 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 245 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.h | 50 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_mgt.c | 1160 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_mgt.h | 97 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_nic.c | 283 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_user.h | 7 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_utils.c | 57 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.c | 390 | ||||
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.h | 15 | 
15 files changed, 3143 insertions, 1024 deletions
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile index 35148513c47..97820c23ece 100644 --- a/drivers/infiniband/hw/nes/Makefile +++ b/drivers/infiniband/hw/nes/Makefile @@ -1,3 +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 +iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 0c9f0aa5d4e..3b2a6dc8ea9 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -68,7 +68,6 @@ MODULE_VERSION(DRV_VERSION);  int max_mtu = 9000;  int interrupt_mod_interval = 0; -  /* Interoperability */  int mpa_version = 1;  module_param(mpa_version, int, 0644); @@ -79,12 +78,7 @@ int disable_mpa_crc = 0;  module_param(disable_mpa_crc, int, 0644);  MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC"); -unsigned int send_first = 0; -module_param(send_first, int, 0644); -MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); - - -unsigned int nes_drv_opt = 0; +unsigned int nes_drv_opt = NES_DRV_OPT_DISABLE_INT_MOD | NES_DRV_OPT_ENABLE_PAU;  module_param(nes_drv_opt, int, 0644);  MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters"); @@ -96,7 +90,7 @@ unsigned int wqm_quanta = 0x10000;  module_param(wqm_quanta, int, 0644);  MODULE_PARM_DESC(wqm_quanta, "WQM quanta"); -static unsigned int limit_maxrdreqsz; +static bool limit_maxrdreqsz;  module_param(limit_maxrdreqsz, bool, 0644);  MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes"); @@ -117,6 +111,16 @@ static struct pci_device_id nes_pci_table[] = {  MODULE_DEVICE_TABLE(pci, nes_pci_table); +/* registered nes netlink callbacks */ +static struct ibnl_client_cbs nes_nl_cb_table[] = { +	[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb}, +	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb}, +	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb}, +	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb}, +	[RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb}, +	[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb} +}; +  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; @@ -130,9 +134,6 @@ static struct notifier_block nes_net_notifier = {  	.notifier_call = nes_net_event  }; - - -  /**   * nes_inetaddr_event   */ @@ -143,7 +144,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,  	struct net_device *event_netdev = ifa->ifa_dev->dev;  	struct nes_device *nesdev;  	struct net_device *netdev; +	struct net_device *upper_dev;  	struct nes_vnic *nesvnic; +	unsigned int is_bonded;  	nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n",  		  &ifa->ifa_address, &ifa->ifa_mask); @@ -152,7 +155,10 @@ static int nes_inetaddr_event(struct notifier_block *notifier,  				nesdev, nesdev->netdev[0]->name);  		netdev = nesdev->netdev[0];  		nesvnic = netdev_priv(netdev); -		if (netdev == event_netdev) { +		upper_dev = netdev_master_upper_dev_get(netdev); +		is_bonded = netif_is_bond_slave(netdev) && +			    (upper_dev == event_netdev); +		if ((netdev == event_netdev) || is_bonded) {  			if (nesvnic->rdma_enabled == 0) {  				nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"  						" RDMA is not enabled.\n", @@ -169,7 +175,10 @@ static int nes_inetaddr_event(struct notifier_block *notifier,  					nes_manage_arp_cache(netdev, netdev->dev_addr,  							ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);  					nesvnic->local_ipaddr = 0; -					return NOTIFY_OK; +					if (is_bonded) +						continue; +					else +						return NOTIFY_OK;  					break;  				case NETDEV_UP:  					nes_debug(NES_DBG_NETDEV, "event:UP\n"); @@ -178,15 +187,24 @@ static int nes_inetaddr_event(struct notifier_block *notifier,  						nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");  						return NOTIFY_OK;  					} +					/* fall through */ +				case NETDEV_CHANGEADDR:  					/* Add the address to the IP table */ -					nesvnic->local_ipaddr = ifa->ifa_address; +					if (upper_dev) +						nesvnic->local_ipaddr = +							((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address; +					else +						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)); +							ntohl(nesvnic->local_ipaddr));  					nes_manage_arp_cache(netdev, netdev->dev_addr,  							ntohl(nesvnic->local_ipaddr), NES_ARP_ADD); -					return NOTIFY_OK; +					if (is_bonded) +						continue; +					else +						return NOTIFY_OK;  					break;  				default:  					break; @@ -306,6 +324,9 @@ void nes_rem_ref(struct ib_qp *ibqp)  	}  	if (atomic_dec_and_test(&nesqp->refcount)) { +		if (nesqp->pau_mode) +			nes_destroy_pau_qp(nesdev, nesqp); +  		/* Destroy the QP */  		cqp_request = nes_get_cqp_request(nesdev);  		if (cqp_request == NULL) { @@ -434,7 +455,7 @@ static irqreturn_t nes_interrupt(int irq, void *dev_id)  /**   * nes_probe - Device initialization   */ -static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) +static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)  {  	struct net_device *netdev = NULL;  	struct nes_device *nesdev = NULL; @@ -660,9 +681,25 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i  	}  	nes_notifiers_registered++; +	if (ibnl_add_client(RDMA_NL_NES, RDMA_NL_IWPM_NUM_OPS, nes_nl_cb_table)) +		printk(KERN_ERR PFX "%s[%u]: Failed to add netlink callback\n", +			__func__, __LINE__); + +	ret = iwpm_init(RDMA_NL_NES); +	if (ret) { +		printk(KERN_ERR PFX "%s: port mapper initialization failed\n", +				pci_name(pcidev)); +		goto bail7; +	} + +	INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); +  	/* Initialize network devices */ -	if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) +	netdev = nes_netdev_init(nesdev, mmio_regs); +	if (netdev == NULL) { +		ret = -ENOMEM;  		goto bail7; +	}  	/* Register network device */  	ret = register_netdev(netdev); @@ -677,7 +714,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i  	nesdev->netdev_count++;  	nesdev->nesadapter->netdev_count++; -	printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n", +	printk(KERN_INFO PFX "%s: NetEffect RNIC driver successfully loaded.\n",  			pci_name(pcidev));  	return 0; @@ -693,6 +730,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i  	nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",  			nesdev->netdev_count, nesdev->nesadapter->netdev_count); +	ibnl_remove_client(RDMA_NL_NES);  	nes_notifiers_registered--;  	if (nes_notifiers_registered == 0) { @@ -737,11 +775,12 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i  /**   * nes_remove - unload from kernel   */ -static void __devexit nes_remove(struct pci_dev *pcidev) +static void nes_remove(struct pci_dev *pcidev)  {  	struct nes_device *nesdev = pci_get_drvdata(pcidev);  	struct net_device *netdev;  	int netdev_index = 0; +	unsigned long flags;  		if (nesdev->netdev_count) {  			netdev = nesdev->netdev[netdev_index]; @@ -755,6 +794,8 @@ static void __devexit nes_remove(struct pci_dev *pcidev)  				nesdev->nesadapter->netdev_count--;  			}  		} +	ibnl_remove_client(RDMA_NL_NES); +	iwpm_exit(RDMA_NL_NES);  	nes_notifiers_registered--;  	if (nes_notifiers_registered == 0) { @@ -768,6 +809,14 @@ static void __devexit nes_remove(struct pci_dev *pcidev)  	free_irq(pcidev->irq, nesdev);  	tasklet_kill(&nesdev->dpc_tasklet); +	spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); +	if (nesdev->link_recheck) { +		spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); +		cancel_delayed_work_sync(&nesdev->work); +	} else { +		spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); +	} +  	/* Deallocate the Adapter Structure */  	nes_destroy_adapter(nesdev->nesadapter); @@ -789,7 +838,7 @@ static struct pci_driver nes_pci_driver = {  	.name = DRV_NAME,  	.id_table = nes_pci_table,  	.probe = nes_probe, -	.remove = __devexit_p(nes_remove), +	.remove = nes_remove,  };  static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf) @@ -1112,7 +1161,9 @@ static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,  	u32 i = 0;  	struct nes_device *nesdev; -	strict_strtoul(buf, 0, &wqm_quanta_value); +	if (kstrtoul(buf, 0, &wqm_quanta_value) < 0) +		return -EINVAL; +  	list_for_each_entry(nesdev, &nes_dev_list, list) {  		if (i == ee_flsh_adapter) {  			nesdev->nesadapter->wqm_quanta = wqm_quanta_value; diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index b3d145e82b4..bd9d132f11c 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -51,13 +51,15 @@  #include <rdma/ib_pack.h>  #include <rdma/rdma_cm.h>  #include <rdma/iw_cm.h> +#include <rdma/rdma_netlink.h> +#include <rdma/iw_portmap.h>  #define NES_SEND_FIRST_WRITE  #define QUEUE_DISCONNECTS  #define DRV_NAME    "iw_nes" -#define DRV_VERSION "1.5.0.0" +#define DRV_VERSION "1.5.0.1"  #define PFX         DRV_NAME ": "  /* @@ -102,6 +104,7 @@  #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_DRV_OPT_ENABLE_PAU           0x00000400  #define NES_AEQ_EVENT_TIMEOUT         2500  #define NES_DISCONNECT_EVENT_TIMEOUT  2000 @@ -128,6 +131,8 @@  #define NES_DBG_IW_RX       0x00020000  #define NES_DBG_IW_TX       0x00040000  #define NES_DBG_SHUTDOWN    0x00080000 +#define NES_DBG_PAU         0x00100000 +#define NES_DBG_NLMSG       0x00200000  #define NES_DBG_RSVD1       0x10000000  #define NES_DBG_RSVD2       0x20000000  #define NES_DBG_RSVD3       0x40000000 @@ -162,6 +167,7 @@ do { \  #include "nes_context.h"  #include "nes_user.h"  #include "nes_cm.h" +#include "nes_mgt.h"  extern int max_mtu;  #define max_frame_len (max_mtu+ETH_HLEN) @@ -169,7 +175,6 @@ 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 unsigned int wqm_quanta; @@ -202,6 +207,8 @@ 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 atomic_t pau_qps_created; +extern atomic_t pau_qps_destroyed;  extern u32 int_mod_timer_init;  extern u32 int_mod_cq_depth_256; @@ -268,8 +275,19 @@ struct nes_device {  	u8                     napi_isr_ran;  	u8                     disable_rx_flow_control;  	u8                     disable_tx_flow_control; + +	struct delayed_work    work; +	u8                     link_recheck;  }; +/* Receive skb private area - must fit in skb->cb area */ +struct nes_rskb_cb { +	u64                    busaddr; +	u32                    maplen; +	u32                    seqnum; +	u8                     *data_start; +	struct nes_qp          *nesqp; +};  static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad)  { @@ -302,8 +320,8 @@ set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 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_CTX_LOW_IDX]       = 0; +	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX]      = 0;  	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; @@ -383,11 +401,20 @@ static inline void nes_write8(void __iomem *addr, u8 val)  	writeb(val, addr);  } - +enum nes_resource { +	NES_RESOURCE_MW = 1, +	NES_RESOURCE_FAST_MR, +	NES_RESOURCE_PHYS_MR, +	NES_RESOURCE_USER_MR, +	NES_RESOURCE_PD, +	NES_RESOURCE_QP, +	NES_RESOURCE_CQ, +	NES_RESOURCE_ARP +};  static inline int nes_alloc_resource(struct nes_adapter *nesadapter,  		unsigned long *resource_array, u32 max_resources, -		u32 *req_resource_num, u32 *next) +		u32 *req_resource_num, u32 *next, enum nes_resource resource_type)  {  	unsigned long flags;  	u32 resource_num; @@ -398,7 +425,7 @@ static inline int nes_alloc_resource(struct nes_adapter *nesadapter,  	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", __func__); +			printk(KERN_ERR PFX "%s: No available resources [type=%u].\n", __func__, resource_type);  			spin_unlock_irqrestore(&nesadapter->resource_lock, flags);  			return -EMFILE;  		} @@ -507,6 +534,8 @@ void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);  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 *); +void nes_recheck_link_status(struct work_struct *work); +void nes_terminate_timeout(unsigned long context);  /* nes_nic.c */  struct net_device *nes_netdev_init(struct nes_device *, void __iomem *); diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 25ad0f9944c..6f09a72e78d 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2014 Intel Corporation.  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 @@ -34,7 +34,7 @@  #define TCPOPT_TIMESTAMP 8 -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <linux/skbuff.h>  #include <linux/ip.h>  #include <linux/tcp.h> @@ -59,6 +59,7 @@  #include <net/route.h>  #include <net/ip_fib.h>  #include <net/tcp.h> +#include <linux/fcntl.h>  #include "nes.h" @@ -77,26 +78,19 @@ 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 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 mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *); -static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, -	struct nes_vnic *, u16, void *, struct nes_cm_info *); +static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, struct nes_vnic *, u16, void *, struct nes_cm_info *);  static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *); -static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, -	struct nes_cm_node *); -static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, -	struct nes_cm_node *); -static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, -	struct sk_buff *); +static int mini_cm_accept(struct nes_cm_core *, struct nes_cm_node *); +static int mini_cm_reject(struct nes_cm_core *, struct nes_cm_node *); +static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);  static int mini_cm_dealloc_core(struct nes_cm_core *);  static int mini_cm_get(struct nes_cm_core *);  static int mini_cm_set(struct nes_cm_core *, u32, u32); -static void form_cm_frame(struct sk_buff *, struct nes_cm_node *, -	void *, u32, void *, u32, u8); +static void form_cm_frame(struct sk_buff *, struct nes_cm_node *, void *, u32, void *, u32, u8);  static int add_ref_cm_node(struct nes_cm_node *);  static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *); @@ -111,16 +105,14 @@ static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);  static int send_reset(struct nes_cm_node *, struct sk_buff *);  static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);  static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb); -static void process_packet(struct nes_cm_node *, struct sk_buff *, -	struct nes_cm_core *); +static void process_packet(struct nes_cm_node *, struct sk_buff *, struct nes_cm_core *);  static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);  static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);  static void cleanup_retrans_entry(struct nes_cm_node *);  static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);  static void free_retrans_entry(struct nes_cm_node *cm_node); -static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, -	struct sk_buff *skb, int optionsize, int passive); +static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, struct sk_buff *skb, int optionsize, int passive);  /* CM event handler functions */  static void cm_event_connected(struct nes_cm_event *); @@ -130,7 +122,14 @@ static void cm_event_mpa_req(struct nes_cm_event *);  static void cm_event_mpa_reject(struct nes_cm_event *);  static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node); +/* MPA build functions */ +static int cm_build_mpa_frame(struct nes_cm_node *, u8 **, u16 *, u8 *, u8); +static void build_mpa_v2(struct nes_cm_node *, void *, u8); +static void build_mpa_v1(struct nes_cm_node *, void *, u8); +static void build_rdma0_msg(struct nes_cm_node *, struct nes_qp **); +  static void print_core(struct nes_cm_core *core); +static void record_ird_ord(struct nes_cm_node *, u16, u16);  /* External CM API Interface */  /* instance of function pointers for client API */ @@ -159,12 +158,20 @@ atomic_t cm_connecteds;  atomic_t cm_connect_reqs;  atomic_t cm_rejects; +int nes_add_ref_cm_node(struct nes_cm_node *cm_node) +{ +	return add_ref_cm_node(cm_node); +} +int nes_rem_ref_cm_node(struct nes_cm_node *cm_node) +{ +	return rem_ref_cm_node(cm_node->cm_core, cm_node); +}  /**   * create_event   */ -static struct nes_cm_event *create_event(struct nes_cm_node *cm_node, -		enum nes_cm_event_type type) +static struct nes_cm_event *create_event(struct nes_cm_node *	cm_node, +					 enum nes_cm_event_type type)  {  	struct nes_cm_event *event; @@ -186,10 +193,10 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,  	event->cm_info.cm_id = cm_node->cm_id;  	nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, " -		"dst_addr=%08x[%x], src_addr=%08x[%x]\n", -		cm_node, event, type, event->cm_info.loc_addr, -		event->cm_info.loc_port, event->cm_info.rem_addr, -		event->cm_info.rem_port); +		  "dst_addr=%08x[%x], src_addr=%08x[%x]\n", +		  cm_node, event, type, event->cm_info.loc_addr, +		  event->cm_info.loc_port, event->cm_info.rem_addr, +		  event->cm_info.rem_port);  	nes_cm_post_event(event);  	return event; @@ -201,14 +208,19 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,   */  static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)  { +	u8 start_addr = 0; +	u8 *start_ptr = &start_addr; +	u8 **start_buff = &start_ptr; +	u16 buff_len = 0; +  	if (!skb) {  		nes_debug(NES_DBG_CM, "skb set to NULL\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); +	cm_build_mpa_frame(cm_node, start_buff, &buff_len, NULL, MPA_KEY_REQUEST); +	form_cm_frame(skb, cm_node, NULL, 0, *start_buff, buff_len, SET_ACK);  	return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);  } @@ -217,7 +229,12 @@ static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)  static int send_mpa_reject(struct nes_cm_node *cm_node)  { -	struct sk_buff  *skb = NULL; +	struct sk_buff *skb = NULL; +	u8 start_addr = 0; +	u8 *start_ptr = &start_addr; +	u8 **start_buff = &start_ptr; +	u16 buff_len = 0; +	struct ietf_mpa_v1 *mpa_frame;  	skb = dev_alloc_skb(MAX_CM_BUFFER);  	if (!skb) { @@ -226,8 +243,10 @@ static int send_mpa_reject(struct nes_cm_node *cm_node)  	}  	/* send an MPA reject frame */ -	form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame, -			cm_node->mpa_frame_size, SET_ACK | SET_FIN); +	cm_build_mpa_frame(cm_node, start_buff, &buff_len, NULL, MPA_KEY_REPLY); +	mpa_frame = (struct ietf_mpa_v1 *)*start_buff; +	mpa_frame->flags |= IETF_MPA_FLAGS_REJECT; +	form_cm_frame(skb, cm_node, NULL, 0, *start_buff, buff_len, SET_ACK | SET_FIN);  	cm_node->state = NES_CM_STATE_FIN_WAIT1;  	return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0); @@ -239,24 +258,31 @@ static int send_mpa_reject(struct nes_cm_node *cm_node)   * IETF MPA frame   */  static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type, -		u32 len) +		     u32 len)  { -	struct ietf_mpa_frame *mpa_frame; +	struct ietf_mpa_v1 *mpa_frame; +	struct ietf_mpa_v2 *mpa_v2_frame; +	struct ietf_rtr_msg *rtr_msg; +	int mpa_hdr_len; +	int priv_data_len;  	*type = NES_MPA_REQUEST_ACCEPT;  	/* assume req frame is in tcp data payload */ -	if (len < sizeof(struct ietf_mpa_frame)) { +	if (len < sizeof(struct ietf_mpa_v1)) {  		nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);  		return -EINVAL;  	} -	mpa_frame = (struct ietf_mpa_frame *)buffer; -	cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len); +	/* points to the beginning of the frame, which could be MPA V1 or V2 */ +	mpa_frame = (struct ietf_mpa_v1 *)buffer; +	mpa_hdr_len = sizeof(struct ietf_mpa_v1); +	priv_data_len = ntohs(mpa_frame->priv_data_len); +  	/* make sure mpa private data len is less than 512 bytes */ -	if (cm_node->mpa_frame_size > IETF_MAX_PRIV_DATA_LEN) { +	if (priv_data_len > IETF_MAX_PRIV_DATA_LEN) {  		nes_debug(NES_DBG_CM, "The received Length of Private" -			" Data field exceeds 512 octets\n"); +			  " Data field exceeds 512 octets\n");  		return -EINVAL;  	}  	/* @@ -264,11 +290,22 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,  	 * received MPA version and MPA key information  	 *  	 */ -	if (mpa_frame->rev != mpa_version) { +	if (mpa_frame->rev != IETF_MPA_V1 && mpa_frame->rev != IETF_MPA_V2) { +		nes_debug(NES_DBG_CM, "The received mpa version" +			  " is not supported\n"); +		return -EINVAL; +	} +	/* +	* backwards compatibility only +	*/ +	if (mpa_frame->rev > cm_node->mpa_frame_rev) {  		nes_debug(NES_DBG_CM, "The received mpa version" -				" can not be interoperated\n"); +			" can not be interoperated\n");  		return -EINVAL; +	} else { +		cm_node->mpa_frame_rev = mpa_frame->rev;  	} +  	if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {  		if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE)) {  			nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n"); @@ -281,25 +318,109 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,  		}  	} -	if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) { +	if (priv_data_len + mpa_hdr_len != 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); +			" complete (%x + %x != %x)\n", +			priv_data_len, mpa_hdr_len, len);  		return -EINVAL;  	}  	/* make sure it does not exceed the max size */  	if (len > MAX_CM_BUFFER) {  		nes_debug(NES_DBG_CM, "The received ietf buffer was too large" -				" (%x + %x != %x)\n", -				cm_node->mpa_frame_size, -				(u32)sizeof(struct ietf_mpa_frame), len); +			" (%x + %x != %x)\n", +			priv_data_len, mpa_hdr_len, len);  		return -EINVAL;  	} +	cm_node->mpa_frame_size = priv_data_len; + +	switch (mpa_frame->rev) { +	case IETF_MPA_V2: { +		u16 ird_size; +		u16 ord_size; +		u16 rtr_ctrl_ird; +		u16 rtr_ctrl_ord; + +		mpa_v2_frame = (struct ietf_mpa_v2 *)buffer; +		mpa_hdr_len += IETF_RTR_MSG_SIZE; +		cm_node->mpa_frame_size -= IETF_RTR_MSG_SIZE; +		rtr_msg = &mpa_v2_frame->rtr_msg; + +		/* parse rtr message */ +		rtr_ctrl_ird = ntohs(rtr_msg->ctrl_ird); +		rtr_ctrl_ord = ntohs(rtr_msg->ctrl_ord); +		ird_size = rtr_ctrl_ird & IETF_NO_IRD_ORD; +		ord_size = rtr_ctrl_ord & IETF_NO_IRD_ORD; + +		if (!(rtr_ctrl_ird & IETF_PEER_TO_PEER)) { +			/* send reset */ +			return -EINVAL; +		} +		if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD) +			cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD; + +		if (cm_node->mpav2_ird_ord != IETF_NO_IRD_ORD) { +			/* responder */ +			if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) { +				/* we are still negotiating */ +				if (ord_size > NES_MAX_IRD) { +					cm_node->ird_size = NES_MAX_IRD; +				} else { +					cm_node->ird_size = ord_size; +					if (ord_size == 0 && +					(rtr_ctrl_ord & IETF_RDMA0_READ)) { +						cm_node->ird_size = 1; +						nes_debug(NES_DBG_CM, +						"%s: Remote peer doesn't support RDMA0_READ (ord=%u)\n", +							__func__, ord_size); +					} +				} +				if (ird_size > NES_MAX_ORD) +					cm_node->ord_size = NES_MAX_ORD; +				else +					cm_node->ord_size = ird_size; +			} else { /* initiator */ +				if (ord_size > NES_MAX_IRD) { +					nes_debug(NES_DBG_CM, +					"%s: Unable to support the requested (ord =%u)\n", +							__func__, ord_size); +					return -EINVAL; +				} +				cm_node->ird_size = ord_size; + +				if (ird_size > NES_MAX_ORD) { +					cm_node->ord_size = NES_MAX_ORD; +				} else { +					if (ird_size == 0 && +					(rtr_ctrl_ord & IETF_RDMA0_READ)) { +						nes_debug(NES_DBG_CM, +						"%s: Remote peer doesn't support RDMA0_READ (ird=%u)\n", +							__func__, ird_size); +						return -EINVAL; +					} else { +						cm_node->ord_size = ird_size; +					} +				} +			} +		} + +		if (rtr_ctrl_ord & IETF_RDMA0_READ) { +			cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; + +		} else if (rtr_ctrl_ord & IETF_RDMA0_WRITE) { +			cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO; +		} else {        /* Not supported RDMA0 operation */ +			return -EINVAL; +		} +		break; +	} +	case IETF_MPA_V1: +	default: +		break; +	} +  	/* 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); +	memcpy(cm_node->mpa_frame_buf, buffer + mpa_hdr_len, cm_node->mpa_frame_size);  	if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)  		*type = NES_MPA_REQUEST_REJECT; @@ -312,8 +433,8 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,   * node info to build.   */  static void form_cm_frame(struct sk_buff *skb, -	struct nes_cm_node *cm_node, void *options, u32 optionsize, -	void *data, u32 datasize, u8 flags) +			  struct nes_cm_node *cm_node, void *options, u32 optionsize, +			  void *data, u32 datasize, u8 flags)  {  	struct tcphdr *tcph;  	struct iphdr *iph; @@ -322,14 +443,14 @@ static void form_cm_frame(struct sk_buff *skb,  	u16 packetsize = sizeof(*iph);  	packetsize += sizeof(*tcph); -	packetsize +=  optionsize + datasize; +	packetsize += optionsize + datasize; +	skb_trim(skb, 0);  	memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph)); -	skb->len = 0;  	buf = skb_put(skb, packetsize + ETH_HLEN); -	ethh = (struct ethhdr *) buf; +	ethh = (struct ethhdr *)buf;  	buf += ETH_HLEN;  	iph = (struct iphdr *)buf; @@ -337,10 +458,12 @@ static void form_cm_frame(struct sk_buff *skb,  	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)); +	skb_set_transport_header(skb, ETH_HLEN + sizeof(*iph));  	buf += sizeof(*tcph);  	skb->ip_summed = CHECKSUM_PARTIAL; +	if (!(cm_node->netdev->features & NETIF_F_IP_CSUM)) +		skb->ip_summed = CHECKSUM_NONE;  	skb->protocol = htons(0x800);  	skb->data_len = 0;  	skb->mac_len = ETH_HLEN; @@ -350,34 +473,36 @@ static void form_cm_frame(struct sk_buff *skb,  	ethh->h_proto = htons(0x0800);  	iph->version = IPVERSION; -	iph->ihl = 5;		/* 5 * 4Byte words, IP headr len */ +	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->protocol = 0x06;   /* IPPROTO_TCP */ -	iph->saddr = htonl(cm_node->loc_addr); -	iph->daddr = htonl(cm_node->rem_addr); +	iph->saddr = htonl(cm_node->mapped_loc_addr); +	iph->daddr = htonl(cm_node->mapped_rem_addr); -	tcph->source = htons(cm_node->loc_port); -	tcph->dest = htons(cm_node->rem_port); +	tcph->source = htons(cm_node->mapped_loc_port); +	tcph->dest = htons(cm_node->mapped_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 +	} else {  		tcph->ack_seq = 0; +	}  	if (flags & SET_SYN) {  		cm_node->tcp_cntxt.loc_seq_num++;  		tcph->syn = 1; -	} else +	} else {  		cm_node->tcp_cntxt.loc_seq_num += datasize; +	}  	if (flags & SET_FIN) {  		cm_node->tcp_cntxt.loc_seq_num++; @@ -398,9 +523,101 @@ static void form_cm_frame(struct sk_buff *skb,  	skb_shinfo(skb)->nr_frags = 0;  	cm_packets_created++; +} + +/* + * nes_create_sockaddr - Record ip addr and tcp port in a sockaddr struct + */ +static void nes_create_sockaddr(__be32 ip_addr, __be16 port, +				struct sockaddr_storage *addr) +{ +	struct sockaddr_in *nes_sockaddr = (struct sockaddr_in *)addr; +	nes_sockaddr->sin_family = AF_INET; +	memcpy(&nes_sockaddr->sin_addr.s_addr, &ip_addr, sizeof(__be32)); +	nes_sockaddr->sin_port = port; +} + +/* + * nes_create_mapinfo - Create a mapinfo object in the port mapper data base + */ +static int nes_create_mapinfo(struct nes_cm_info *cm_info) +{ +	struct sockaddr_storage local_sockaddr; +	struct sockaddr_storage mapped_sockaddr; + +	nes_create_sockaddr(htonl(cm_info->loc_addr), htons(cm_info->loc_port), +				&local_sockaddr); +	nes_create_sockaddr(htonl(cm_info->mapped_loc_addr), +			htons(cm_info->mapped_loc_port), &mapped_sockaddr); + +	return iwpm_create_mapinfo(&local_sockaddr, +				&mapped_sockaddr, RDMA_NL_NES); +} + +/* + * nes_remove_mapinfo - Remove a mapinfo object from the port mapper data base + *                      and send a remove mapping op message to + *                      the userspace port mapper + */ +static int nes_remove_mapinfo(u32 loc_addr, u16 loc_port, +			u32 mapped_loc_addr, u16 mapped_loc_port) +{ +	struct sockaddr_storage local_sockaddr; +	struct sockaddr_storage mapped_sockaddr; +	nes_create_sockaddr(htonl(loc_addr), htons(loc_port), &local_sockaddr); +	nes_create_sockaddr(htonl(mapped_loc_addr), htons(mapped_loc_port), +				&mapped_sockaddr); + +	iwpm_remove_mapinfo(&local_sockaddr, &mapped_sockaddr); +	return iwpm_remove_mapping(&local_sockaddr, RDMA_NL_NES);  } +/* + * nes_form_pm_msg - Form a port mapper message with mapping info + */ +static void nes_form_pm_msg(struct nes_cm_info *cm_info, +				struct iwpm_sa_data *pm_msg) +{ +	nes_create_sockaddr(htonl(cm_info->loc_addr), htons(cm_info->loc_port), +				&pm_msg->loc_addr); +	nes_create_sockaddr(htonl(cm_info->rem_addr), htons(cm_info->rem_port), +				&pm_msg->rem_addr); +} + +/* + * nes_form_reg_msg - Form a port mapper message with dev info + */ +static void nes_form_reg_msg(struct nes_vnic *nesvnic, +			struct iwpm_dev_data *pm_msg) +{ +	memcpy(pm_msg->dev_name, nesvnic->nesibdev->ibdev.name, +				IWPM_DEVNAME_SIZE); +	memcpy(pm_msg->if_name, nesvnic->netdev->name, IWPM_IFNAME_SIZE); +} + +/* + * nes_record_pm_msg - Save the received mapping info + */ +static void nes_record_pm_msg(struct nes_cm_info *cm_info, +			struct iwpm_sa_data *pm_msg) +{ +	struct sockaddr_in *mapped_loc_addr = +			(struct sockaddr_in *)&pm_msg->mapped_loc_addr; +	struct sockaddr_in *mapped_rem_addr = +			(struct sockaddr_in *)&pm_msg->mapped_rem_addr; + +	if (mapped_loc_addr->sin_family == AF_INET) { +		cm_info->mapped_loc_addr = +			ntohl(mapped_loc_addr->sin_addr.s_addr); +		cm_info->mapped_loc_port = ntohs(mapped_loc_addr->sin_port); +	} +	if (mapped_rem_addr->sin_family == AF_INET) { +		cm_info->mapped_rem_addr = +			ntohl(mapped_rem_addr->sin_addr.s_addr); +		cm_info->mapped_rem_port = ntohs(mapped_rem_addr->sin_port); +	} +}  /**   * print_core - dump a cm core @@ -413,7 +630,7 @@ static void print_core(struct nes_cm_core *core)  		return;  	nes_debug(NES_DBG_CM, "---------------------------------------------\n"); -	nes_debug(NES_DBG_CM, "State         : %u \n",  core->state); +	nes_debug(NES_DBG_CM, "State         : %u \n", core->state);  	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)); @@ -423,6 +640,162 @@ static void print_core(struct nes_cm_core *core)  	nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");  } +static void record_ird_ord(struct nes_cm_node *cm_node, +					u16 conn_ird, u16 conn_ord) +{ +	if (conn_ird > NES_MAX_IRD) +		conn_ird = NES_MAX_IRD; + +	if (conn_ord > NES_MAX_ORD) +		conn_ord = NES_MAX_ORD; + +	cm_node->ird_size = conn_ird; +	cm_node->ord_size = conn_ord; +} + +/** + * cm_build_mpa_frame - build a MPA V1 frame or MPA V2 frame + */ +static int cm_build_mpa_frame(struct nes_cm_node *cm_node, u8 **start_buff, +			      u16 *buff_len, u8 *pci_mem, u8 mpa_key) +{ +	int ret = 0; + +	*start_buff = (pci_mem) ? pci_mem : &cm_node->mpa_frame_buf[0]; + +	switch (cm_node->mpa_frame_rev) { +	case IETF_MPA_V1: +		*start_buff = (u8 *)*start_buff + sizeof(struct ietf_rtr_msg); +		*buff_len = sizeof(struct ietf_mpa_v1) + cm_node->mpa_frame_size; +		build_mpa_v1(cm_node, *start_buff, mpa_key); +		break; +	case IETF_MPA_V2: +		*buff_len = sizeof(struct ietf_mpa_v2) + cm_node->mpa_frame_size; +		build_mpa_v2(cm_node, *start_buff, mpa_key); +		break; +	default: +		ret = -EINVAL; +	} +	return ret; +} + +/** + * build_mpa_v2 - build a MPA V2 frame + */ +static void build_mpa_v2(struct nes_cm_node *cm_node, +			 void *start_addr, u8 mpa_key) +{ +	struct ietf_mpa_v2 *mpa_frame = (struct ietf_mpa_v2 *)start_addr; +	struct ietf_rtr_msg *rtr_msg = &mpa_frame->rtr_msg; +	u16 ctrl_ird; +	u16 ctrl_ord; + +	/* initialize the upper 5 bytes of the frame */ +	build_mpa_v1(cm_node, start_addr, mpa_key); +	mpa_frame->flags |= IETF_MPA_V2_FLAG; /* set a bit to indicate MPA V2 */ +	mpa_frame->priv_data_len += htons(IETF_RTR_MSG_SIZE); + +	/* initialize RTR msg */ +	if (cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) { +		ctrl_ird = IETF_NO_IRD_ORD; +		ctrl_ord = IETF_NO_IRD_ORD; +	} else { +		ctrl_ird = cm_node->ird_size & IETF_NO_IRD_ORD; +		ctrl_ord = cm_node->ord_size & IETF_NO_IRD_ORD; +	} +	ctrl_ird |= IETF_PEER_TO_PEER; +	ctrl_ird |= IETF_FLPDU_ZERO_LEN; + +	switch (mpa_key) { +	case MPA_KEY_REQUEST: +		ctrl_ord |= IETF_RDMA0_WRITE; +		ctrl_ord |= IETF_RDMA0_READ; +		break; +	case MPA_KEY_REPLY: +		switch (cm_node->send_rdma0_op) { +		case SEND_RDMA_WRITE_ZERO: +			ctrl_ord |= IETF_RDMA0_WRITE; +			break; +		case SEND_RDMA_READ_ZERO: +			ctrl_ord |= IETF_RDMA0_READ; +			break; +		} +	} +	rtr_msg->ctrl_ird = htons(ctrl_ird); +	rtr_msg->ctrl_ord = htons(ctrl_ord); +} + +/** + * build_mpa_v1 - build a MPA V1 frame + */ +static void build_mpa_v1(struct nes_cm_node *cm_node, void *start_addr, u8 mpa_key) +{ +	struct ietf_mpa_v1 *mpa_frame = (struct ietf_mpa_v1 *)start_addr; + +	switch (mpa_key) { +	case MPA_KEY_REQUEST: +		memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE); +		break; +	case MPA_KEY_REPLY: +		memcpy(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE); +		break; +	} +	mpa_frame->flags = IETF_MPA_FLAGS_CRC; +	mpa_frame->rev = cm_node->mpa_frame_rev; +	mpa_frame->priv_data_len = htons(cm_node->mpa_frame_size); +} + +static void build_rdma0_msg(struct nes_cm_node *cm_node, struct nes_qp **nesqp_addr) +{ +	u64 u64temp; +	struct nes_qp *nesqp = *nesqp_addr; +	struct nes_hw_qp_wqe *wqe = &nesqp->hwqp.sq_vbase[0]; + +	u64temp = (unsigned long)nesqp->nesuqp_addr; +	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_FRAG0_LOW_IDX] = 0; +	wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0; + +	switch (cm_node->send_rdma0_op) { +	case SEND_RDMA_WRITE_ZERO: +		nes_debug(NES_DBG_CM, "Sending first write.\n"); +		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_LENGTH0_IDX] = 0; +		wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; +		break; + +	case SEND_RDMA_READ_ZERO: +	default: +		if (cm_node->send_rdma0_op != SEND_RDMA_READ_ZERO) +			WARN(1, "Unsupported RDMA0 len operation=%u\n", +			     cm_node->send_rdma0_op); +		nes_debug(NES_DBG_CM, "Sending first rdma operation.\n"); +		wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = +			cpu_to_le32(NES_IWARP_SQ_OP_RDMAR); +		wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX] = 1; +		wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX] = 0; +		wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] = 0; +		wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_STAG_IDX] = 1; +		wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 1; +		break; +	} + +	if (nesqp->sq_kmapped) { +		nesqp->sq_kmapped = 0; +		kunmap(nesqp->page); +	} + +	/*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; +}  /**   * schedule_nes_timer @@ -430,14 +803,13 @@ static void print_core(struct nes_cm_core *core)   *			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) +		       enum nes_timer_type type, int send_retrans, +		       int close_when_complete)  { -	unsigned long  flags; +	unsigned long flags;  	struct nes_cm_core *cm_core = cm_node->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) @@ -454,7 +826,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,  	new_send->close_when_complete = close_when_complete;  	if (type == NES_TIMER_TYPE_CLOSE) { -		new_send->timetosend += (HZ/10); +		new_send->timetosend += (HZ / 10);  		if (cm_node->recv_entry) {  			kfree(new_send);  			WARN_ON(1); @@ -475,7 +847,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,  		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); +				  "(jiffies = %lu)\n", new_send, jiffies);  			new_send->timetosend = jiffies;  			ret = NETDEV_TX_OK;  		} else { @@ -489,12 +861,8 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,  		}  	} -	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); -	} +	if (!timer_pending(&cm_core->tcp_timer)) +		mod_timer(&cm_core->tcp_timer, new_send->timetosend);  	return ret;  } @@ -504,6 +872,7 @@ static void nes_retrans_expired(struct nes_cm_node *cm_node)  	struct iw_cm_id *cm_id = cm_node->cm_id;  	enum nes_cm_node_state state = cm_node->state;  	cm_node->state = NES_CM_STATE_CLOSED; +  	switch (state) {  	case NES_CM_STATE_SYN_RCVD:  	case NES_CM_STATE_CLOSING: @@ -536,10 +905,10 @@ static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)  		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)); +				  "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; @@ -548,10 +917,10 @@ static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)  		} 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)); +				  "refcount = %d: HIT A " +				  "NES_TIMER_TYPE_CLOSE with nothing " +				  "to do!!!\n", nesqp->hwqp.qp_id, cm_id, +				  atomic_read(&nesqp->refcount));  		}  	} else if (rem_node) {  		/* TIME_WAIT state */ @@ -580,11 +949,12 @@ static void nes_cm_timer_tick(unsigned long pass)  	int ret = NETDEV_TX_OK;  	struct list_head timer_list; +  	INIT_LIST_HEAD(&timer_list);  	spin_lock_irqsave(&cm_core->ht_lock, flags);  	list_for_each_safe(list_node, list_core_temp, -				&cm_core->connected_nodes) { +			   &cm_core->connected_nodes) {  		cm_node = container_of(list_node, struct nes_cm_node, list);  		if ((cm_node->recv_entry) || (cm_node->send_entry)) {  			add_ref_cm_node(cm_node); @@ -595,18 +965,19 @@ static void nes_cm_timer_tick(unsigned long pass)  	list_for_each_safe(list_node, list_core_temp, &timer_list) {  		cm_node = container_of(list_node, struct nes_cm_node, -					timer_entry); +				       timer_entry);  		recv_entry = cm_node->recv_entry;  		if (recv_entry) {  			if (time_after(recv_entry->timetosend, jiffies)) {  				if (nexttimeout > recv_entry->timetosend || -						!settimer) { +				    !settimer) {  					nexttimeout = recv_entry->timetosend;  					settimer = 1;  				} -			} else +			} else {  				handle_recv_entry(cm_node, 1); +			}  		}  		spin_lock_irqsave(&cm_node->retrans_list_lock, flags); @@ -617,8 +988,8 @@ static void nes_cm_timer_tick(unsigned long pass)  			if (time_after(send_entry->timetosend, jiffies)) {  				if (cm_node->state != NES_CM_STATE_TSA) {  					if ((nexttimeout > -						send_entry->timetosend) || -						!settimer) { +					     send_entry->timetosend) || +					    !settimer) {  						nexttimeout =  							send_entry->timetosend;  						settimer = 1; @@ -630,13 +1001,13 @@ static void nes_cm_timer_tick(unsigned long pass)  			}  			if ((cm_node->state == NES_CM_STATE_TSA) || -				(cm_node->state == NES_CM_STATE_CLOSED)) { +			    (cm_node->state == NES_CM_STATE_CLOSED)) {  				free_retrans_entry(cm_node);  				break;  			}  			if (!send_entry->retranscount || -				!send_entry->retrycount) { +			    !send_entry->retrycount) {  				cm_packets_dropped++;  				free_retrans_entry(cm_node); @@ -645,28 +1016,28 @@ static void nes_cm_timer_tick(unsigned long pass)  				nes_retrans_expired(cm_node);  				cm_node->state = NES_CM_STATE_CLOSED;  				spin_lock_irqsave(&cm_node->retrans_list_lock, -					flags); +						  flags);  				break;  			}  			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); +				  "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); +					       flags);  			ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);  			spin_lock_irqsave(&cm_node->retrans_list_lock, flags);  			if (ret != NETDEV_TX_OK) {  				nes_debug(NES_DBG_CM, "rexmit failed for " -					"node=%p\n", cm_node); +					  "node=%p\n", cm_node);  				cm_packets_bounced++;  				send_entry->retrycount--;  				nexttimeout = jiffies + NES_SHORT_TIME; @@ -676,18 +1047,18 @@ static void nes_cm_timer_tick(unsigned long pass)  				cm_packets_sent++;  			}  			nes_debug(NES_DBG_CM, "Packet Sent: retrans count = " -				"%u, retry count = %u.\n", -				send_entry->retranscount, -				send_entry->retrycount); +				  "%u, retry count = %u.\n", +				  send_entry->retranscount, +				  send_entry->retrycount);  			if (send_entry->send_retrans) {  				send_entry->retranscount--;  				timetosend = (NES_RETRY_TIMEOUT << -					(NES_DEFAULT_RETRANS - send_entry->retranscount)); +					      (NES_DEFAULT_RETRANS - send_entry->retranscount));  				send_entry->timetosend = jiffies + -					min(timetosend, NES_MAX_TIMEOUT); +							 min(timetosend, NES_MAX_TIMEOUT);  				if (nexttimeout > send_entry->timetosend || -					!settimer) { +				    !settimer) {  					nexttimeout = send_entry->timetosend;  					settimer = 1;  				} @@ -696,11 +1067,11 @@ static void nes_cm_timer_tick(unsigned long pass)  				close_when_complete =  					send_entry->close_when_complete;  				nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n", -					cm_node, cm_node->state); +					  cm_node, cm_node->state);  				free_retrans_entry(cm_node);  				if (close_when_complete)  					rem_ref_cm_node(cm_node->cm_core, -						cm_node); +							cm_node);  			}  		} while (0); @@ -709,10 +1080,8 @@ static void nes_cm_timer_tick(unsigned long pass)  	}  	if (settimer) { -		if (!timer_pending(&cm_core->tcp_timer)) { -			cm_core->tcp_timer.expires  = nexttimeout; -			add_timer(&cm_core->tcp_timer); -		} +		if (!timer_pending(&cm_core->tcp_timer)) +			mod_timer(&cm_core->tcp_timer, nexttimeout);  	}  } @@ -721,13 +1090,13 @@ static void nes_cm_timer_tick(unsigned long pass)   * send_syn   */  static int send_syn(struct nes_cm_node *cm_node, u32 sendack, -	struct sk_buff *skb) +		    struct sk_buff *skb)  {  	int ret;  	int flags = SET_SYN;  	char optionsbuffer[sizeof(struct option_mss) + -		sizeof(struct option_windowscale) + sizeof(struct option_base) + -		TCP_OPTIONS_PADDING]; +			   sizeof(struct option_windowscale) + sizeof(struct option_base) + +			   TCP_OPTIONS_PADDING];  	int optionssize = 0;  	/* Sending MSS option */ @@ -854,7 +1223,7 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)   * 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) +				     u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)  {  	unsigned long flags;  	struct list_head *hte; @@ -868,12 +1237,15 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,  	list_for_each_entry(cm_node, hte, 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)) { +			  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->mapped_loc_addr == loc_addr) && +			(cm_node->mapped_loc_port == loc_port) && +			(cm_node->mapped_rem_addr == rem_addr) && +			(cm_node->mapped_rem_port == rem_port)) { +  			add_ref_cm_node(cm_node);  			spin_unlock_irqrestore(&cm_core->ht_lock, flags);  			return cm_node; @@ -890,19 +1262,29 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,   * 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) +					nes_addr_t dst_addr, u16 dst_port, +					enum nes_cm_listener_state listener_state, int local)  {  	unsigned long flags;  	struct nes_cm_listener *listen_node; +	nes_addr_t listen_addr; +	u16 listen_port;  	/* walk list and find cm_node associated with this session ID */  	spin_lock_irqsave(&cm_core->listen_list_lock, flags);  	list_for_each_entry(listen_node, &cm_core->listen_list.list, list) { +		if (local) { +			listen_addr = listen_node->loc_addr; +			listen_port = listen_node->loc_port; +		} else { +			listen_addr = listen_node->mapped_loc_addr; +			listen_port = listen_node->mapped_loc_port; +		}  		/* 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)) { +		if (((listen_addr == dst_addr) || +		     listen_addr == 0x00000000) && +		    (listen_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; @@ -914,7 +1296,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,  	return NULL;  } -  /**   * add_hte_node - add a cm node to the hash table   */ @@ -927,7 +1308,7 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node  		return -EINVAL;  	nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n", -		cm_node); +		  cm_node);  	spin_lock_irqsave(&cm_core->ht_lock, flags); @@ -946,7 +1327,7 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node   * mini_cm_dec_refcnt_listen   */  static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, -	struct nes_cm_listener *listener, int free_hanging_nodes) +				     struct nes_cm_listener *listener, int free_hanging_nodes)  {  	int ret = -EINVAL;  	int err = 0; @@ -957,8 +1338,8 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  	struct list_head reset_list;  	nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, " -		"refcnt=%d\n", listener, free_hanging_nodes, -		atomic_read(&listener->ref_count)); +		  "refcnt=%d\n", listener, free_hanging_nodes, +		  atomic_read(&listener->ref_count));  	/* free non-accelerated child nodes for this listener */  	INIT_LIST_HEAD(&reset_list);  	if (free_hanging_nodes) { @@ -966,7 +1347,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  		list_for_each_safe(list_pos, list_temp,  				   &g_cm_core->connected_nodes) {  			cm_node = container_of(list_pos, struct nes_cm_node, -				list); +					       list);  			if ((cm_node->listener == listener) &&  			    (!cm_node->accelerated)) {  				add_ref_cm_node(cm_node); @@ -978,7 +1359,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  	list_for_each_safe(list_pos, list_temp, &reset_list) {  		cm_node = container_of(list_pos, struct nes_cm_node, -				reset_entry); +				       reset_entry);  		{  			struct nes_cm_node *loopback = cm_node->loopbackpartner;  			enum nes_cm_node_state old_state; @@ -990,7 +1371,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  					err = send_reset(cm_node, NULL);  					if (err) {  						cm_node->state = -							 NES_CM_STATE_CLOSED; +							NES_CM_STATE_CLOSED;  						WARN_ON(1);  					} else {  						old_state = cm_node->state; @@ -1036,8 +1417,18 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  		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_manage_apbvt(listener->nesvnic, +				listener->mapped_loc_port, +				PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), +				NES_MANAGE_APBVT_DEL); + +			nes_remove_mapinfo(listener->loc_addr, +					listener->loc_port, +					listener->mapped_loc_addr, +					listener->mapped_loc_port); +			nes_debug(NES_DBG_NLMSG, +					"Delete APBVT mapped_loc_port = %04X\n", +					listener->mapped_loc_port);  		}  		nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener); @@ -1052,8 +1443,8 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,  	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)); +				  " with non-zero pending accepts=%u\n", +				  listener, atomic_read(&listener->pend_accepts_cnt));  	}  	return ret; @@ -1064,7 +1455,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,   * mini_cm_del_listen   */  static int mini_cm_del_listen(struct nes_cm_core *cm_core, -		struct nes_cm_listener *listener) +			      struct nes_cm_listener *listener)  {  	listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;  	listener->cm_id = NULL; /* going to be destroyed pretty soon */ @@ -1076,9 +1467,8 @@ static int mini_cm_del_listen(struct nes_cm_core *cm_core,   * mini_cm_accelerated   */  static inline int mini_cm_accelerated(struct nes_cm_core *cm_core, -		struct nes_cm_node *cm_node) +				      struct nes_cm_node *cm_node)  { -	u32 was_timer_set;  	cm_node->accelerated = 1;  	if (cm_node->accept_pend) { @@ -1088,11 +1478,8 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,  		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); -	} +	if (!timer_pending(&cm_core->tcp_timer)) +		mod_timer(&cm_core->tcp_timer, (jiffies + NES_SHORT_TIME));  	return 0;  } @@ -1104,20 +1491,26 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,  static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpindex)  {  	struct rtable *rt; -	struct flowi fl;  	struct neighbour *neigh;  	int rc = arpindex; +	struct net_device *netdev;  	struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter; -	memset(&fl, 0, sizeof fl); -	fl.nl_u.ip4_u.daddr = htonl(dst_ip); -	if (ip_route_output_key(&init_net, &rt, &fl)) { +	rt = ip_route_output(&init_net, htonl(dst_ip), 0, 0, 0); +	if (IS_ERR(rt)) {  		printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n", -				__func__, dst_ip); +		       __func__, dst_ip);  		return rc;  	} -	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev); +	if (netif_is_bond_slave(nesvnic->netdev)) +		netdev = netdev_master_upper_dev_get(nesvnic->netdev); +	else +		netdev = nesvnic->netdev; + +	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev); + +	rcu_read_lock();  	if (neigh) {  		if (neigh->nud_state & NUD_VALID) {  			nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X" @@ -1125,29 +1518,29 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi  				  neigh->ha, ntohl(rt->rt_gateway));  			if (arpindex >= 0) { -				if (!memcmp(nesadapter->arp_table[arpindex].mac_addr, -							neigh->ha, ETH_ALEN)){ +				if (ether_addr_equal(nesadapter->arp_table[arpindex].mac_addr, neigh->ha)) {  					/* Mac address same as in nes_arp_table */ -					neigh_release(neigh); -					ip_rt_put(rt); -					return rc; +					goto out;  				}  				nes_manage_arp_cache(nesvnic->netdev, -						nesadapter->arp_table[arpindex].mac_addr, -						dst_ip, NES_ARP_DELETE); +						     nesadapter->arp_table[arpindex].mac_addr, +						     dst_ip, NES_ARP_DELETE);  			}  			nes_manage_arp_cache(nesvnic->netdev, neigh->ha,  					     dst_ip, NES_ARP_ADD);  			rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,  					   NES_ARP_RESOLVE); +		} else { +			neigh_event_send(neigh, NULL);  		} -		neigh_release(neigh);  	} +out: +	rcu_read_unlock(); -	if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) -		neigh_event_send(rt->dst.neighbour, NULL); +	if (neigh) +		neigh_release(neigh);  	ip_rt_put(rt);  	return rc; @@ -1157,8 +1550,8 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi   * 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_vnic *nesvnic, struct nes_cm_info *cm_info, +					struct nes_cm_listener *listener)  {  	struct nes_cm_node *cm_node;  	struct timespec ts; @@ -1177,7 +1570,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,  	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; + +	cm_node->mapped_loc_addr = cm_info->mapped_loc_addr; +	cm_node->mapped_rem_addr = cm_info->mapped_rem_addr; +	cm_node->mapped_loc_port = cm_info->mapped_loc_port; +	cm_node->mapped_rem_port = cm_info->mapped_rem_port; + +	cm_node->mpa_frame_rev = mpa_version; +	cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; +	cm_node->mpav2_ird_ord = 0; +	cm_node->ird_size = 0; +	cm_node->ord_size = 0; +  	nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",  		  &cm_node->loc_addr, cm_node->loc_port,  		  &cm_node->rem_addr, cm_node->rem_port); @@ -1187,7 +1591,7 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,  	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); +		  cm_node->cm_id);  	spin_lock_init(&cm_node->retrans_list_lock); @@ -1198,11 +1602,11 @@ static struct nes_cm_node *make_cm_node(struct nes_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; +				     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 - VLAN_HLEN; +				 sizeof(struct tcphdr) - ETH_HLEN - VLAN_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); @@ -1218,13 +1622,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,  	cm_node->loopbackpartner = NULL;  	/* get the mac addr for the remote node */ -	if (ipv4_is_loopback(htonl(cm_node->rem_addr))) -		arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE); -	else { -		oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE); -		arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex); - -	} +	oldarpindex = nes_arp_table(nesdev, cm_node->mapped_rem_addr, +				NULL, NES_ARP_RESOLVE); +	arpindex = nes_addr_resolve_neigh(nesvnic, +				cm_node->mapped_rem_addr, oldarpindex);  	if (arpindex < 0) {  		kfree(cm_node);  		return NULL; @@ -1256,7 +1657,7 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)   * rem_ref_cm_node - destroy an instance of a cm node   */  static int rem_ref_cm_node(struct nes_cm_core *cm_core, -	struct nes_cm_node *cm_node) +			   struct nes_cm_node *cm_node)  {  	unsigned long flags;  	struct nes_qp *nesqp; @@ -1286,11 +1687,14 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,  		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); +			nes_manage_apbvt(cm_node->nesvnic, cm_node->mapped_loc_port, +					 PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn), +					 NES_MANAGE_APBVT_DEL);  		} +		nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n", +					cm_node->mapped_loc_port); +		nes_remove_mapinfo(cm_node->loc_addr, cm_node->loc_port, +			cm_node->mapped_loc_addr, cm_node->mapped_loc_port);  	}  	atomic_dec(&cm_core->node_cnt); @@ -1310,7 +1714,7 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,   * process_options   */  static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, -	u32 optionsize, u32 syn_packet) +			   u32 optionsize, u32 syn_packet)  {  	u32 tmp;  	u32 offset = 0; @@ -1328,15 +1732,15 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,  			continue;  		case OPTION_NUMBER_MSS:  			nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d " -				"Size: %d\n", __func__, -				all_options->as_mss.length, offset, optionsize); +				  "Size: %d\n", __func__, +				  all_options->as_mss.length, offset, optionsize);  			got_mss_option = 1;  			if (all_options->as_mss.length != 4) {  				return 1;  			} else {  				tmp = ntohs(all_options->as_mss.mss);  				if (tmp > 0 && tmp < -					cm_node->tcp_cntxt.mss) +				    cm_node->tcp_cntxt.mss)  					cm_node->tcp_cntxt.mss = tmp;  			}  			break; @@ -1344,12 +1748,9 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,  			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); +				  all_options->as_base.optionnum);  			break;  		}  		offset += all_options->as_base.length; @@ -1368,8 +1769,8 @@ static void drop_packet(struct sk_buff *skb)  static void handle_fin_pkt(struct nes_cm_node *cm_node)  {  	nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. " -		"refcnt=%d\n", cm_node, cm_node->state, -		atomic_read(&cm_node->ref_count)); +		  "refcnt=%d\n", cm_node, cm_node->state, +		  atomic_read(&cm_node->ref_count));  	switch (cm_node->state) {  	case NES_CM_STATE_SYN_RCVD:  	case NES_CM_STATE_SYN_SENT: @@ -1393,7 +1794,7 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node)  		cleanup_retrans_entry(cm_node);  		cm_node->state = NES_CM_STATE_CLOSING;  		send_ack(cm_node, NULL); -		/* Wait for ACK as this is simultanous close.. +		/* Wait for ACK as this is simultaneous close..  		* After we receive ACK, do not send anything..  		* Just rm the node.. Done.. */  		break; @@ -1435,7 +1836,20 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  		nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "  			"listener=%p state=%d\n", __func__, __LINE__, cm_node,  			cm_node->listener, cm_node->state); -		active_open_err(cm_node, skb, reset); +		switch (cm_node->mpa_frame_rev) { +		case IETF_MPA_V2: +			cm_node->mpa_frame_rev = IETF_MPA_V1; +			/* send a syn and goto syn sent state */ +			cm_node->state = NES_CM_STATE_SYN_SENT; +			if (send_syn(cm_node, 0, NULL)) { +				active_open_err(cm_node, skb, reset); +			} +			break; +		case IETF_MPA_V1: +		default: +			active_open_err(cm_node, skb, reset); +			break; +		}  		break;  	case NES_CM_STATE_MPAREQ_RCVD:  		atomic_inc(&cm_node->passive_state); @@ -1471,21 +1885,21 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)  { - -	int	ret = 0; +	int ret = 0;  	int datasize = skb->len;  	u8 *dataloc = skb->data;  	enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN; -	u32     res_type; +	u32 res_type; +  	ret = parse_mpa(cm_node, dataloc, &res_type, datasize);  	if (ret) {  		nes_debug(NES_DBG_CM, "didn't like MPA Request\n");  		if (cm_node->state == NES_CM_STATE_MPAREQ_SENT) {  			nes_debug(NES_DBG_CM, "%s[%u] create abort for " -				"cm_node=%p listener=%p state=%d\n", __func__, -				__LINE__, cm_node, cm_node->listener, -				cm_node->state); +				  "cm_node=%p listener=%p state=%d\n", __func__, +				  __LINE__, cm_node, cm_node->listener, +				  cm_node->state);  			active_open_err(cm_node, skb, 1);  		} else {  			passive_open_err(cm_node, skb, 1); @@ -1495,16 +1909,15 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)  	switch (cm_node->state) {  	case NES_CM_STATE_ESTABLISHED: -		if (res_type == NES_MPA_REQUEST_REJECT) { +		if (res_type == NES_MPA_REQUEST_REJECT)  			/*BIG problem as we are receiving the MPA.. So should -			* not be REJECT.. This is Passive Open.. We can -			* only receive it Reject for Active Open...*/ +			 * not be REJECT.. This is Passive Open.. We can +			 * only receive it Reject for Active Open...*/  			WARN_ON(1); -		}  		cm_node->state = NES_CM_STATE_MPAREQ_RCVD;  		type = NES_CM_EVENT_MPA_REQ;  		atomic_set(&cm_node->passive_state, -				NES_PASSIVE_STATE_INDICATED); +			   NES_PASSIVE_STATE_INDICATED);  		break;  	case NES_CM_STATE_MPAREQ_SENT:  		cleanup_retrans_entry(cm_node); @@ -1531,8 +1944,8 @@ static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)  	case NES_CM_STATE_SYN_SENT:  	case NES_CM_STATE_MPAREQ_SENT:  		nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p " -			"listener=%p state=%d\n", __func__, __LINE__, cm_node, -			cm_node->listener, cm_node->state); +			  "listener=%p state=%d\n", __func__, __LINE__, cm_node, +			  cm_node->listener, cm_node->state);  		active_open_err(cm_node, skb, 1);  		break;  	case NES_CM_STATE_ESTABLISHED: @@ -1546,11 +1959,11 @@ static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)  }  static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph, -	struct sk_buff *skb) +		     struct sk_buff *skb)  {  	int err; -	err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1; +	err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num)) ? 0 : 1;  	if (err)  		active_open_err(cm_node, skb, 1); @@ -1558,7 +1971,7 @@ static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,  }  static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph, -	struct sk_buff *skb) +		     struct sk_buff *skb)  {  	int err = 0;  	u32 seq; @@ -1566,21 +1979,22 @@ static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,  	u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;  	u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;  	u32 rcv_wnd; +  	seq = ntohl(tcph->seq);  	ack_seq = ntohl(tcph->ack_seq);  	rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;  	if (ack_seq != loc_seq_num)  		err = 1; -	else if (!between(seq, rcv_nxt, (rcv_nxt+rcv_wnd))) +	else if (!between(seq, rcv_nxt, (rcv_nxt + rcv_wnd)))  		err = 1;  	if (err) {  		nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p " -			"listener=%p state=%d\n", __func__, __LINE__, cm_node, -			cm_node->listener, cm_node->state); +			  "listener=%p state=%d\n", __func__, __LINE__, cm_node, +			  cm_node->listener, cm_node->state);  		indicate_pkt_err(cm_node, skb);  		nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X " -			"rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt, -			rcv_wnd); +			  "rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt, +			  rcv_wnd);  	}  	return err;  } @@ -1590,9 +2004,8 @@ static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,   * is created with a listener or it may comein as rexmitted packet which in   * that case will be just dropped.   */ -  static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, -	struct tcphdr *tcph) +			   struct tcphdr *tcph)  {  	int ret;  	u32 inc_sequence; @@ -1611,15 +2024,15 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  	case NES_CM_STATE_LISTENING:  		/* Passive OPEN */  		if (atomic_read(&cm_node->listener->pend_accepts_cnt) > -				cm_node->listener->backlog) { +		    cm_node->listener->backlog) {  			nes_debug(NES_DBG_CM, "drop syn due to backlog " -				"pressure \n"); +				  "pressure \n");  			cm_backlog_drops++;  			passive_open_err(cm_node, skb, 0);  			break;  		}  		ret = handle_tcp_options(cm_node, tcph, skb, optionsize, -			1); +					 1);  		if (ret) {  			passive_open_err(cm_node, skb, 0);  			/* drop pkt */ @@ -1653,9 +2066,8 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  }  static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, -	struct tcphdr *tcph) +			      struct tcphdr *tcph)  { -  	int ret;  	u32 inc_sequence;  	int optionsize; @@ -1674,7 +2086,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  		ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);  		if (ret) {  			nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n", -				cm_node); +				  cm_node);  			break;  		}  		cleanup_retrans_entry(cm_node); @@ -1713,12 +2125,13 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  }  static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, -	struct tcphdr *tcph) +			  struct tcphdr *tcph)  {  	int datasize = 0;  	u32 inc_sequence;  	int ret = 0;  	int optionsize; +  	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);  	if (check_seq(cm_node, tcph, skb)) @@ -1739,8 +2152,9 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  		if (datasize) {  			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;  			handle_rcv_mpa(cm_node, skb); -		} else  /* rcvd ACK only */ +		} else { /* rcvd ACK only */  			dev_kfree_skb_any(skb); +		}  		break;  	case NES_CM_STATE_ESTABLISHED:  		/* Passive OPEN */ @@ -1748,16 +2162,18 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  		if (datasize) {  			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;  			handle_rcv_mpa(cm_node, skb); -		} else +		} else {  			drop_packet(skb); +		}  		break;  	case NES_CM_STATE_MPAREQ_SENT:  		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);  		if (datasize) {  			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;  			handle_rcv_mpa(cm_node, skb); -		} else  /* Could be just an ack pkt.. */ +		} else { /* Could be just an ack pkt.. */  			dev_kfree_skb_any(skb); +		}  		break;  	case NES_CM_STATE_LISTENING:  		cleanup_retrans_entry(cm_node); @@ -1798,14 +2214,15 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,  static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, -	struct sk_buff *skb, int optionsize, int passive) +			      struct sk_buff *skb, int optionsize, int passive)  {  	u8 *optionsloc = (u8 *)&tcph[1]; +  	if (optionsize) {  		if (process_options(cm_node, optionsloc, optionsize, -			(u32)tcph->syn)) { +				    (u32)tcph->syn)) {  			nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", -				__func__, cm_node); +				  __func__, cm_node);  			if (passive)  				passive_open_err(cm_node, skb, 1);  			else @@ -1815,7 +2232,7 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,  	}  	cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) << -			cm_node->tcp_cntxt.snd_wscale; +				     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; @@ -1826,18 +2243,18 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,   * active_open_err() will send reset() if flag set..   * It will also send ABORT event.   */ -  static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb, -	int reset) +			    int reset)  {  	cleanup_retrans_entry(cm_node);  	if (reset) {  		nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, " -				"state=%d\n", cm_node, cm_node->state); +			  "state=%d\n", cm_node, cm_node->state);  		add_ref_cm_node(cm_node);  		send_reset(cm_node, skb); -	} else +	} else {  		dev_kfree_skb_any(skb); +	}  	cm_node->state = NES_CM_STATE_CLOSED;  	create_event(cm_node, NES_CM_EVENT_ABORTED); @@ -1847,15 +2264,14 @@ static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,   * passive_open_err() will either do a reset() or will free up the skb and   * remove the cm_node.   */ -  static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb, -	int reset) +			     int reset)  {  	cleanup_retrans_entry(cm_node);  	cm_node->state = NES_CM_STATE_CLOSED;  	if (reset) {  		nes_debug(NES_DBG_CM, "passive_open_err sending RST for " -			"cm_node=%p state =%d\n", cm_node, cm_node->state); +			  "cm_node=%p state =%d\n", cm_node, cm_node->state);  		send_reset(cm_node, skb);  	} else {  		dev_kfree_skb_any(skb); @@ -1870,6 +2286,7 @@ static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,  static void free_retrans_entry(struct nes_cm_node *cm_node)  {  	struct nes_timer_entry *send_entry; +  	send_entry = cm_node->send_entry;  	if (send_entry) {  		cm_node->send_entry = NULL; @@ -1893,26 +2310,28 @@ static void cleanup_retrans_entry(struct nes_cm_node *cm_node)   * Returns skb if to be freed, else it will return NULL if already used..   */  static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, -	struct nes_cm_core *cm_core) +			   struct nes_cm_core *cm_core)  { -	enum nes_tcpip_pkt_type	pkt_type = NES_PKT_TYPE_UNKNOWN; +	enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;  	struct tcphdr *tcph = tcp_hdr(skb); -	u32     fin_set = 0; +	u32 fin_set = 0;  	int ret = 0; +  	skb_pull(skb, ip_hdr(skb)->ihl << 2);  	nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d " -		"ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn, -		tcph->ack, tcph->rst, tcph->fin); +		  "ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn, +		  tcph->ack, tcph->rst, tcph->fin); -	if (tcph->rst) +	if (tcph->rst) {  		pkt_type = NES_PKT_TYPE_RST; -	else if (tcph->syn) { +	} else if (tcph->syn) {  		pkt_type = NES_PKT_TYPE_SYN;  		if (tcph->ack)  			pkt_type = NES_PKT_TYPE_SYNACK; -	} else if (tcph->ack) +	} else if (tcph->ack) {  		pkt_type = NES_PKT_TYPE_ACK; +	}  	if (tcph->fin)  		fin_set = 1; @@ -1943,17 +2362,21 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,   * mini_cm_listen - create a listen node with params   */  static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, -	struct nes_vnic *nesvnic, struct nes_cm_info *cm_info) +			struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)  {  	struct nes_cm_listener *listener; +	struct iwpm_dev_data pm_reg_msg; +	struct iwpm_sa_data pm_msg;  	unsigned long flags; +	int iwpm_err = 0;  	nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n", -		cm_info->loc_addr, cm_info->loc_port); +		  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); +	listener = find_listener(cm_core, cm_info->loc_addr, cm_info->loc_port, +				NES_CM_LISTENER_EITHER_STATE, 1); +  	if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {  		/* find automatically incs ref count ??? */  		atomic_dec(&listener->ref_count); @@ -1962,6 +2385,22 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,  	}  	if (!listener) { +		nes_form_reg_msg(nesvnic, &pm_reg_msg); +		iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_NES); +		if (iwpm_err) { +			nes_debug(NES_DBG_NLMSG, +			"Port Mapper reg pid fail (err = %d).\n", iwpm_err); +		} +		if (iwpm_valid_pid() && !iwpm_err) { +			nes_form_pm_msg(cm_info, &pm_msg); +			iwpm_err = iwpm_add_mapping(&pm_msg, RDMA_NL_NES); +			if (iwpm_err) +				nes_debug(NES_DBG_NLMSG, +				"Port Mapper query fail (err = %d).\n", iwpm_err); +			else +				nes_record_pm_msg(cm_info, &pm_msg); +		} +  		/* create a CM listen node (1/2 node to compare incoming traffic to) */  		listener = kzalloc(sizeof(*listener), GFP_ATOMIC);  		if (!listener) { @@ -1969,8 +2408,10 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,  			return NULL;  		} -		listener->loc_addr = htonl(cm_info->loc_addr); -		listener->loc_port = htons(cm_info->loc_port); +		listener->loc_addr = cm_info->loc_addr; +		listener->loc_port = cm_info->loc_port; +		listener->mapped_loc_addr = cm_info->mapped_loc_addr; +		listener->mapped_loc_port = cm_info->mapped_loc_port;  		listener->reused_node = 0;  		atomic_set(&listener->ref_count, 1); @@ -1999,9 +2440,9 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,  	}  	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); +		  " listener = %p, backlog = %d, cm_id = %p.\n", +		  cm_info->loc_addr, cm_info->loc_port, +		  listener, listener->backlog, listener->cm_id);  	return listener;  } @@ -2011,26 +2452,20 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,   * mini_cm_connect - make a connection node with params   */  static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, -	struct nes_vnic *nesvnic, u16 private_data_len, -	void *private_data, struct nes_cm_info *cm_info) +					   struct nes_vnic *nesvnic, u16 private_data_len, +					   void *private_data, struct nes_cm_info *cm_info)  {  	int ret = 0;  	struct nes_cm_node *cm_node;  	struct nes_cm_listener *loopbackremotelistener;  	struct nes_cm_node *loopbackremotenode;  	struct nes_cm_info loopback_cm_info; -	u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len; -	struct ietf_mpa_frame *mpa_frame = NULL; +	u8 *start_buff;  	/* create a CM connection node */  	cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);  	if (!cm_node)  		return NULL; -	mpa_frame = &cm_node->mpa_frame; -	memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE); -	mpa_frame->flags = IETF_MPA_FLAGS_CRC; -	mpa_frame->rev =  IETF_MPA_VERSION; -	mpa_frame->priv_data_len = htons(private_data_len);  	/* set our node side to client (active) side */  	cm_node->tcp_cntxt.client = 1; @@ -2038,17 +2473,21 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,  	if (cm_info->loc_addr == cm_info->rem_addr) {  		loopbackremotelistener = find_listener(cm_core, -				ntohl(nesvnic->local_ipaddr), cm_node->rem_port, -				NES_CM_LISTENER_ACTIVE_STATE); +			cm_node->mapped_loc_addr, cm_node->mapped_rem_port, +			NES_CM_LISTENER_ACTIVE_STATE, 0);  		if (loopbackremotelistener == NULL) {  			create_event(cm_node, NES_CM_EVENT_ABORTED);  		} else {  			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.mapped_loc_port = +				cm_info->mapped_rem_port; +			loopback_cm_info.mapped_rem_port = +				cm_info->mapped_loc_port;  			loopback_cm_info.cm_id = loopbackremotelistener->cm_id;  			loopbackremotenode = make_cm_node(cm_core, nesvnic, -				&loopback_cm_info, loopbackremotelistener); +							  &loopback_cm_info, loopbackremotelistener);  			if (!loopbackremotenode) {  				rem_ref_cm_node(cm_node->cm_core, cm_node);  				return NULL; @@ -2059,7 +2498,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,  				NES_CM_DEFAULT_RCV_WND_SCALE;  			cm_node->loopbackpartner = loopbackremotenode;  			memcpy(loopbackremotenode->mpa_frame_buf, private_data, -				private_data_len); +			       private_data_len);  			loopbackremotenode->mpa_frame_size = private_data_len;  			/* we are done handling this state. */ @@ -2087,12 +2526,10 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,  		return cm_node;  	} -	/* set our node side to client (active) side */ -	cm_node->tcp_cntxt.client = 1; -	/* init our MPA frame ptr */ -	memcpy(mpa_frame->priv_data, private_data, private_data_len); +	start_buff = &cm_node->mpa_frame_buf[0] + sizeof(struct ietf_mpa_v2); +	cm_node->mpa_frame_size = private_data_len; -	cm_node->mpa_frame_size = mpa_frame_size; +	memcpy(start_buff, private_data, private_data_len);  	/* send a syn and goto syn sent state */  	cm_node->state = NES_CM_STATE_SYN_SENT; @@ -2101,18 +2538,19 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,  	if (ret) {  		/* error in sending the syn free up the cm_node struct */  		nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest " -			"addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n", -			cm_node->rem_addr, cm_node->rem_port, cm_node, -			cm_node->cm_id); +			  "addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n", +			  cm_node->rem_addr, cm_node->rem_port, cm_node, +			  cm_node->cm_id);  		rem_ref_cm_node(cm_node->cm_core, cm_node);  		cm_node = NULL;  	} -	if (cm_node) +	if (cm_node) {  		nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X," -			"port=0x%04x, cm_node=%p, cm_id = %p.\n", -			cm_node->rem_addr, cm_node->rem_port, cm_node, -			cm_node->cm_id); +			  "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;  } @@ -2122,8 +2560,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,   * mini_cm_accept - accept a connection   * This function is never called   */ -static int mini_cm_accept(struct nes_cm_core *cm_core, -	struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) +static int mini_cm_accept(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)  {  	return 0;  } @@ -2132,8 +2569,7 @@ static int mini_cm_accept(struct nes_cm_core *cm_core,  /**   * mini_cm_reject - reject and teardown a connection   */ -static int mini_cm_reject(struct nes_cm_core *cm_core, -	struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) +static int mini_cm_reject(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)  {  	int ret = 0;  	int err = 0; @@ -2143,7 +2579,7 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,  	struct nes_cm_node *loopback = cm_node->loopbackpartner;  	nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n", -		__func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state); +		  __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);  	if (cm_node->tcp_cntxt.client)  		return ret; @@ -2164,8 +2600,9 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,  					err = send_reset(cm_node, NULL);  					if (err)  						WARN_ON(1); -				} else +				} else {  					cm_id->add_ref(cm_id); +				}  			}  		}  	} else { @@ -2240,7 +2677,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod  	case NES_CM_STATE_TSA:  		if (cm_node->send_entry)  			printk(KERN_ERR "ERROR Close got called from STATE_TSA " -				"send_entry=%p\n", cm_node->send_entry); +			       "send_entry=%p\n", cm_node->send_entry);  		ret = rem_ref_cm_node(cm_core, cm_node);  		break;  	} @@ -2253,7 +2690,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod   * node state machine   */  static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, -	struct nes_vnic *nesvnic, struct sk_buff *skb) +			    struct nes_vnic *nesvnic, struct sk_buff *skb)  {  	struct nes_cm_node *cm_node = NULL;  	struct nes_cm_listener *listener = NULL; @@ -2265,9 +2702,8 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  	if (!skb)  		return 0; -	if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) { +	if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr))  		return 0; -	}  	iph = (struct iphdr *)skb->data;  	tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr)); @@ -2277,6 +2713,12 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  	nfo.rem_addr = ntohl(iph->saddr);  	nfo.rem_port = ntohs(tcph->source); +	/* If port mapper is available these should be mapped address info */ +	nfo.mapped_loc_addr = ntohl(iph->daddr); +	nfo.mapped_loc_port = ntohs(tcph->dest); +	nfo.mapped_rem_addr = ntohl(iph->saddr); +	nfo.mapped_rem_port = ntohs(tcph->source); +  	tmp_daddr = cpu_to_be32(iph->daddr);  	tmp_saddr = cpu_to_be32(iph->saddr); @@ -2285,8 +2727,8 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  	do {  		cm_node = find_node(cm_core, -			nfo.rem_port, nfo.rem_addr, -			nfo.loc_port, nfo.loc_addr); +				    nfo.mapped_rem_port, nfo.mapped_rem_addr, +				    nfo.mapped_loc_port, nfo.mapped_loc_addr);  		if (!cm_node) {  			/* Only type of packet accepted are for */ @@ -2295,9 +2737,9 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  				skb_handled = 0;  				break;  			} -			listener = find_listener(cm_core, nfo.loc_addr, -				nfo.loc_port, -				NES_CM_LISTENER_ACTIVE_STATE); +			listener = find_listener(cm_core, nfo.mapped_loc_addr, +					nfo.mapped_loc_port, +					NES_CM_LISTENER_ACTIVE_STATE, 0);  			if (!listener) {  				nfo.cm_id = NULL;  				nfo.conn_type = 0; @@ -2308,10 +2750,10 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  			nfo.cm_id = listener->cm_id;  			nfo.conn_type = listener->conn_type;  			cm_node = make_cm_node(cm_core, nesvnic, &nfo, -				listener); +					       listener);  			if (!cm_node) {  				nes_debug(NES_DBG_CM, "Unable to allocate " -					"node\n"); +					  "node\n");  				cm_packets_dropped++;  				atomic_dec(&listener->ref_count);  				dev_kfree_skb_any(skb); @@ -2327,9 +2769,13 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,  			}  			add_ref_cm_node(cm_node);  		} else if (cm_node->state == NES_CM_STATE_TSA) { -			rem_ref_cm_node(cm_core, cm_node); -			atomic_inc(&cm_accel_dropped_pkts); -			dev_kfree_skb_any(skb); +			if (cm_node->nesqp->pau_mode) +				nes_queue_mgt_skbs(skb, nesvnic, cm_node->nesqp); +			else { +				rem_ref_cm_node(cm_core, cm_node); +				atomic_inc(&cm_accel_dropped_pkts); +				dev_kfree_skb_any(skb); +			}  			break;  		}  		skb_reset_network_header(skb); @@ -2359,7 +2805,7 @@ static struct nes_cm_core *nes_cm_alloc_core(void)  	init_timer(&cm_core->tcp_timer);  	cm_core->tcp_timer.function = nes_cm_timer_tick; -	cm_core->mtu   = NES_CM_DEFAULT_MTU; +	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; @@ -2397,9 +2843,8 @@ static int mini_cm_dealloc_core(struct nes_cm_core *cm_core)  	barrier(); -	if (timer_pending(&cm_core->tcp_timer)) { +	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); @@ -2454,8 +2899,8 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod  		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); +						  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); @@ -2465,15 +2910,15 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod  	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); +		(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); +		(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); +		(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; @@ -2482,24 +2927,24 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod  	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); +						    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->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)); +		  " 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)); @@ -2520,7 +2965,7 @@ int nes_cm_disconn(struct nes_qp *nesqp)  	work = kzalloc(sizeof *work, GFP_ATOMIC);  	if (!work) -		return -ENOMEM; /* Timer will clean up */ +		return -ENOMEM;  /* Timer will clean up */  	nes_add_ref(&nesqp->ibqp);  	work->nesqp = nesqp; @@ -2540,7 +2985,7 @@ static void nes_disconnect_worker(struct work_struct *work)  	kfree(dwork);  	nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", -			nesqp->last_aeq, nesqp->hwqp.qp_id); +		  nesqp->last_aeq, nesqp->hwqp.qp_id);  	nes_cm_disconn_true(nesqp);  	nes_rem_ref(&nesqp->ibqp);  } @@ -2559,7 +3004,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  	u16 last_ae;  	u8 original_hw_tcp_state;  	u8 original_ibqp_state; -	enum iw_cm_event_status disconn_status = IW_CM_EVENT_STATUS_OK; +	int disconn_status = 0;  	int issue_disconn = 0;  	int issue_close = 0;  	int issue_flush = 0; @@ -2576,7 +3021,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  	/* 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); +			  nesqp->hwqp.qp_id);  		spin_unlock_irqrestore(&nesqp->lock, flags);  		return -1;  	} @@ -2585,13 +3030,14 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  	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; +	original_ibqp_state = nesqp->ibqp_state;  	last_ae = nesqp->last_aeq;  	if (nesqp->term_flags) {  		issue_disconn = 1;  		issue_close = 1;  		nesqp->cm_id = NULL; +		del_timer(&nesqp->terminate_timer);  		if (nesqp->flush_issued == 0) {  			nesqp->flush_issued = 1;  			issue_flush = 1; @@ -2601,7 +3047,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {  		issue_disconn = 1;  		if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) -			disconn_status = IW_CM_EVENT_STATUS_RESET; +			disconn_status = -ECONNRESET;  	}  	if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || @@ -2628,7 +3074,8 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			ibevent.device = nesqp->ibqp.device;  			ibevent.event = nesqp->terminate_eventtype;  			ibevent.element.qp = &nesqp->ibqp; -			nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); +			if (nesqp->ibqp.event_handler) +				nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);  		}  	} @@ -2643,16 +3090,16 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			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)); +				  " 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));  			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); +					  "returned, ret=%d\n", ret);  		}  		if (issue_close) { @@ -2662,7 +3109,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			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.status = 0;  			cm_event.provider_data = cm_id->provider_data;  			cm_event.local_addr = cm_id->local_addr;  			cm_event.remote_addr = cm_id->remote_addr; @@ -2670,9 +3117,8 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			cm_event.private_data_len = 0;  			ret = cm_id->event_handler(cm_id, &cm_event); -			if (ret) { +			if (ret)  				nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); -			}  			cm_id->rem_ref(cm_id);  		} @@ -2712,8 +3158,8 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)  			if (nesqp->lsmm_mr)  				nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);  			pci_free_consistent(nesdev->pcidev, -					nesqp->private_data_len+sizeof(struct ietf_mpa_frame), -					nesqp->ietf_frame, nesqp->ietf_frame_pbase); +					    nesqp->private_data_len + nesqp->ietf_frame_size, +					    nesqp->ietf_frame, nesqp->ietf_frame_pbase);  		}  	} @@ -2752,6 +3198,14 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	struct ib_phys_buf ibphysbuf;  	struct nes_pd *nespd;  	u64 tagged_offset; +	u8 mpa_frame_offset = 0; +	struct ietf_mpa_v2 *mpa_v2_frame; +	u8 start_addr = 0; +	u8 *start_ptr = &start_addr; +	u8 **start_buff = &start_ptr; +	u16 buff_len = 0; +	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; +	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;  	ibqp = nes_get_qp(cm_id->device, conn_param->qpn);  	if (!ibqp) @@ -2780,11 +3234,11 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		rem_ref_cm_node(cm_node->cm_core, cm_node);  		return -ECONNRESET;  	} -  	/* associate the node with the QP */  	nesqp->cm_node = (void *)cm_node;  	cm_node->nesqp = nesqp; +  	nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",  		nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);  	atomic_inc(&cm_accepts); @@ -2792,53 +3246,53 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",  			netdev_refcnt_read(nesvnic->netdev)); +	nesqp->ietf_frame_size = sizeof(struct ietf_mpa_v2);  	/* 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); +						 nesqp->ietf_frame_size + 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"); +		nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");  		return -ENOMEM;  	} +	mpa_v2_frame = (struct ietf_mpa_v2 *)nesqp->ietf_frame; +	if (cm_node->mpa_frame_rev == IETF_MPA_V1) +		mpa_frame_offset = 4; -	/* 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); +	if (cm_node->mpa_frame_rev == IETF_MPA_V1 || +			cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) { +		record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); +	} -	memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data, -			conn_param->private_data_len); +	memcpy(mpa_v2_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; +	cm_build_mpa_frame(cm_node, start_buff, &buff_len, nesqp->ietf_frame, MPA_KEY_REPLY); +	nesqp->private_data_len = conn_param->private_data_len;  	/* 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) { +	if (raddr->sin_addr.s_addr != laddr->sin_addr.s_addr) {  		u64temp = (unsigned long)nesqp;  		nesibdev = nesvnic->nesibdev;  		nespd = nesqp->nespd; -		ibphysbuf.addr = nesqp->ietf_frame_pbase; -		ibphysbuf.size = conn_param->private_data_len + -					sizeof(struct ietf_mpa_frame); -		tagged_offset = (u64)(unsigned long)nesqp->ietf_frame; +		ibphysbuf.addr = nesqp->ietf_frame_pbase + mpa_frame_offset; +		ibphysbuf.size = buff_len; +		tagged_offset = (u64)(unsigned long)*start_buff;  		ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd, -						&ibphysbuf, 1, -						IB_ACCESS_LOCAL_WRITE, -						&tagged_offset); +						   &ibphysbuf, 1, +						   IB_ACCESS_LOCAL_WRITE, +						   &tagged_offset);  		if (!ibmr) {  			nes_debug(NES_DBG_CM, "Unable to register memory region" -					"for lSMM for cm_node = %p \n", -					cm_node); +				  "for lSMM for cm_node = %p \n", +				  cm_node);  			pci_free_consistent(nesdev->pcidev, -				nesqp->private_data_len+sizeof(struct ietf_mpa_frame), -				nesqp->ietf_frame, nesqp->ietf_frame_pbase); +					    nesqp->private_data_len + nesqp->ietf_frame_size, +					    nesqp->ietf_frame, nesqp->ietf_frame_pbase);  			return -ENOMEM;  		} @@ -2846,22 +3300,20 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		ibmr->device = nespd->ibpd.device;  		nesqp->lsmm_mr = ibmr; -		u64temp |= NES_SW_CONTEXT_ALIGN>>1; +		u64temp |= NES_SW_CONTEXT_ALIGN >> 1;  		set_wqe_64bit_value(wqe->wqe_words, -			NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, -			u64temp); +				    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); +				    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)); +			cpu_to_le32(buff_len);  		set_wqe_64bit_value(wqe->wqe_words, -					NES_IWARP_SQ_WQE_FRAG0_LOW_IDX, -					(u64)(unsigned long)nesqp->ietf_frame); +				    NES_IWARP_SQ_WQE_FRAG0_LOW_IDX, +				    (u64)(unsigned long)(*start_buff));  		wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = -			cpu_to_le32(conn_param->private_data_len + -			sizeof(struct ietf_mpa_frame)); +			cpu_to_le32(buff_len);  		wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;  		if (nesqp->sq_kmapped) {  			nesqp->sq_kmapped = 0; @@ -2870,48 +3322,42 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		nesqp->nesqp_context->ird_ord_sizes |=  			cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | -			NES_QPCONTEXT_ORDIRD_WRPDU); +				    NES_QPCONTEXT_ORDIRD_WRPDU);  	} else {  		nesqp->nesqp_context->ird_ord_sizes |=  			cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);  	}  	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; +	nesqp->active_conn = 0;  	if (cm_node->state == NES_CM_STATE_TSA)  		nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n", -			cm_node); +			  cm_node);  	nes_cm_init_tsa_conn(nesqp, cm_node);  	nesqp->nesqp_context->tcpPorts[0] = -		cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); +				cpu_to_le16(cm_node->mapped_loc_port);  	nesqp->nesqp_context->tcpPorts[1] = -		cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); +				cpu_to_le16(cm_node->mapped_rem_port); -	if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) -		nesqp->nesqp_context->ip0 = -			cpu_to_le32(ntohl(nesvnic->local_ipaddr)); -	else -		nesqp->nesqp_context->ip0 = -			cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); +	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);  	nesqp->nesqp_context->misc2 |= cpu_to_le32( -			(u32)PCI_FUNC(nesdev->pcidev->devfn) << -			NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); +		(u32)PCI_FUNC(nesdev->pcidev->devfn) << +		NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);  	nesqp->nesqp_context->arp_index_vlan |=  		cpu_to_le32(nes_arp_table(nesdev, -			le32_to_cpu(nesqp->nesqp_context->ip0), NULL, -			NES_ARP_RESOLVE) << 16); +					  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)); @@ -2921,23 +3367,20 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	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); +		cpu_to_le32((u32)cm_node->ord_size);  	memset(&nes_quad, 0, sizeof(nes_quad));  	nes_quad.DstIpAdrIndex =  		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); -	if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) -		nes_quad.SrcIpadr = nesvnic->local_ipaddr; -	else -		nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; -	nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; -	nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; +	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr); +	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port); +	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);  	/* Produce hash key */  	crc_value = get_crc_value(&nes_quad);  	nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);  	nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n", -		nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask); +		  nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);  	nesqp->hte_index &= adapter->hte_index_mask;  	nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index); @@ -2945,29 +3388,28 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	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)); - +		  "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + " +		  "private data length=%u.\n", nesqp->hwqp.qp_id, +		  ntohl(raddr->sin_addr.s_addr), ntohs(raddr->sin_port), +		  ntohl(laddr->sin_addr.s_addr), ntohs(laddr->sin_port), +		  le32_to_cpu(nesqp->nesqp_context->rcv_nxt), +		  le32_to_cpu(nesqp->nesqp_context->snd_nxt), +		  buff_len);  	/* notify OF layer that accept event was successful */  	cm_id->add_ref(cm_id);  	nes_add_ref(&nesqp->ibqp);  	cm_event.event = IW_CM_EVENT_ESTABLISHED; -	cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; +	cm_event.status = 0;  	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; +	cm_event.ird = cm_node->ird_size; +	cm_event.ord = cm_node->ord_size; +  	ret = cm_id->event_handler(cm_id, &cm_event);  	attr.qp_state = IB_QPS_RTS;  	nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); @@ -2976,12 +3418,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  			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); +		       conn_param->private_data, conn_param->private_data_len);  		create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);  	}  	if (ret)  		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " -			"ret=%d\n", __func__, __LINE__, ret); +		       "ret=%d\n", __func__, __LINE__, ret);  	return 0;  } @@ -2994,34 +3436,28 @@ int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)  {  	struct nes_cm_node *cm_node;  	struct nes_cm_node *loopback; -  	struct nes_cm_core *cm_core; +	u8 *start_buff;  	atomic_inc(&cm_rejects); -	cm_node = (struct nes_cm_node *) cm_id->provider_data; +	cm_node = (struct nes_cm_node *)cm_id->provider_data;  	loopback = cm_node->loopbackpartner;  	cm_core = cm_node->cm_core;  	cm_node->cm_id = cm_id; -	cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len; -	if (cm_node->mpa_frame_size > MAX_CM_BUFFER) +	if (pdata_len + sizeof(struct ietf_mpa_v2) > MAX_CM_BUFFER)  		return -EINVAL; -	memcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);  	if (loopback) {  		memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);  		loopback->mpa_frame.priv_data_len = pdata_len; -		loopback->mpa_frame_size = sizeof(struct ietf_mpa_frame) + -				pdata_len; +		loopback->mpa_frame_size = pdata_len;  	} else { -		memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len); -		cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len); +		start_buff = &cm_node->mpa_frame_buf[0] + sizeof(struct ietf_mpa_v2); +		cm_node->mpa_frame_size = pdata_len; +		memcpy(start_buff, pdata, pdata_len);  	} - -	cm_node->mpa_frame.rev = mpa_version; -	cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT; - -	return cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node); +	return cm_core->api->reject(cm_core, cm_node);  } @@ -3038,7 +3474,14 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	struct nes_cm_node *cm_node;  	struct nes_cm_info cm_info;  	int apbvt_set = 0; - +	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; +	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr; +	struct iwpm_dev_data pm_reg_msg; +	struct iwpm_sa_data pm_msg; +	int iwpm_err = 0; + +	if (cm_id->remote_addr.ss_family != AF_INET) +		return -ENOSYS;  	ibqp = nes_get_qp(cm_id->device, conn_param->qpn);  	if (!ibqp)  		return -EINVAL; @@ -3048,66 +3491,95 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	nesvnic = to_nesvnic(nesqp->ibqp.device);  	if (!nesvnic)  		return -EINVAL; -	nesdev  = nesvnic->nesdev; +	nesdev = nesvnic->nesdev;  	if (!nesdev)  		return -EINVAL; -	if (!(cm_id->local_addr.sin_port) || !(cm_id->remote_addr.sin_port)) +	if (!laddr->sin_port || !raddr->sin_port)  		return -EINVAL;  	nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = " -		"0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id, -		ntohl(nesvnic->local_ipaddr), -		ntohl(cm_id->remote_addr.sin_addr.s_addr), -		ntohs(cm_id->remote_addr.sin_port), -		ntohl(cm_id->local_addr.sin_addr.s_addr), -		ntohs(cm_id->local_addr.sin_port)); +		  "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id, +		  ntohl(nesvnic->local_ipaddr), ntohl(raddr->sin_addr.s_addr), +		  ntohs(raddr->sin_port), ntohl(laddr->sin_addr.s_addr), +		  ntohs(laddr->sin_port));  	atomic_inc(&cm_connects);  	nesqp->active_conn = 1;  	/* cache the cm_id in the qp */  	nesqp->cm_id = cm_id; -  	cm_id->provider_data = nesqp; -  	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); +		  conn_param->private_data_len); + +	/* set up the connection params for the node */ +	cm_info.loc_addr = ntohl(laddr->sin_addr.s_addr); +	cm_info.loc_port = ntohs(laddr->sin_port); +	cm_info.rem_addr = ntohl(raddr->sin_addr.s_addr); +	cm_info.rem_port = ntohs(raddr->sin_port); +	cm_info.cm_id = cm_id; +	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; -	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), +	/* No port mapper available, go with the specified peer information */ +	cm_info.mapped_loc_addr = cm_info.loc_addr; +	cm_info.mapped_loc_port = cm_info.loc_port; +	cm_info.mapped_rem_addr = cm_info.rem_addr; +	cm_info.mapped_rem_port = cm_info.rem_port; + +	nes_form_reg_msg(nesvnic, &pm_reg_msg); +	iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_NES); +	if (iwpm_err) { +		nes_debug(NES_DBG_NLMSG, +			"Port Mapper reg pid fail (err = %d).\n", iwpm_err); +	} +	if (iwpm_valid_pid() && !iwpm_err) { +		nes_form_pm_msg(&cm_info, &pm_msg); +		iwpm_err = iwpm_add_and_query_mapping(&pm_msg, RDMA_NL_NES); +		if (iwpm_err) +			nes_debug(NES_DBG_NLMSG, +			"Port Mapper query fail (err = %d).\n", iwpm_err); +		else +			nes_record_pm_msg(&cm_info, &pm_msg); +	} + +	if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) { +		nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,  			PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);  		apbvt_set = 1;  	} -	/* set up the connection params for the node */ -	cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr); -	cm_info.loc_port = htons(cm_id->local_addr.sin_port); -	cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr); -	cm_info.rem_port = htons(cm_id->remote_addr.sin_port); -	cm_info.cm_id = cm_id; -	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; +	if (nes_create_mapinfo(&cm_info)) +		return -ENOMEM;  	cm_id->add_ref(cm_id);  	/* create a connect CM node connection */  	cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, -		conn_param->private_data_len, (void *)conn_param->private_data, -		&cm_info); +					  conn_param->private_data_len, (void *)conn_param->private_data, +					  &cm_info);  	if (!cm_node) {  		if (apbvt_set) -			nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), -				PCI_FUNC(nesdev->pcidev->devfn), -				NES_MANAGE_APBVT_DEL); - +			nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port, +					 PCI_FUNC(nesdev->pcidev->devfn), +					 NES_MANAGE_APBVT_DEL); + +		nes_debug(NES_DBG_NLMSG, "Delete mapped_loc_port = %04X\n", +				cm_info.mapped_loc_port); +		nes_remove_mapinfo(cm_info.loc_addr, cm_info.loc_port, +			cm_info.mapped_loc_addr, cm_info.mapped_loc_port);  		cm_id->rem_ref(cm_id);  		return -ENOMEM;  	} +	record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); +	if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO && +				cm_node->ord_size == 0) +		cm_node->ord_size = 1; +  	cm_node->apbvt_set = apbvt_set;  	nesqp->cm_node = cm_node;  	cm_node->nesqp = nesqp; @@ -3126,10 +3598,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)  	struct nes_cm_listener *cm_node;  	struct nes_cm_info cm_info;  	int err; +	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;  	nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n", -			cm_id, ntohs(cm_id->local_addr.sin_port)); +		  cm_id, ntohs(laddr->sin_port)); +	if (cm_id->local_addr.ss_family != AF_INET) +		return -ENOSYS;  	nesvnic = to_nesvnic(cm_id->device);  	if (!nesvnic)  		return -EINVAL; @@ -3138,34 +3613,39 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)  			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); +			nesvnic->local_ipaddr, laddr->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.loc_addr = ntohl(nesvnic->local_ipaddr); +	cm_info.loc_port = ntohs(laddr->sin_port);  	cm_info.backlog = backlog;  	cm_info.cm_id = cm_id;  	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; +	/* No port mapper available, go with the specified info */ +	cm_info.mapped_loc_addr = cm_info.loc_addr; +	cm_info.mapped_loc_port = cm_info.loc_port;  	cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);  	if (!cm_node) {  		printk(KERN_ERR "%s[%u] Error returned from listen API call\n", -				__func__, __LINE__); +		       __func__, __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 (nes_create_mapinfo(&cm_info)) +			return -ENOMEM; + +		err = nes_manage_apbvt(nesvnic, cm_node->mapped_loc_port, +				       PCI_FUNC(nesvnic->nesdev->pcidev->devfn), +				       NES_MANAGE_APBVT_ADD);  		if (err) {  			printk(KERN_ERR "nes_manage_apbvt call returned %d.\n", -				err); +			       err);  			g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);  			return err;  		} @@ -3202,13 +3682,13 @@ int nes_destroy_listen(struct iw_cm_id *cm_id)  int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)  {  	int rc = 0; +  	cm_packets_received++; -	if ((g_cm_core) && (g_cm_core->api)) { +	if ((g_cm_core) && (g_cm_core->api))  		rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb); -	} else { +	else  		nes_debug(NES_DBG_CM, "Unable to process packet for CM," -				" cm is not setup properly.\n"); -	} +			  " cm is not setup properly.\n");  	return rc;  } @@ -3223,11 +3703,10 @@ 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) { +	if (g_cm_core)  		return 0; -	} else { +	else  		return -ENOMEM; -	}  } @@ -3248,7 +3727,6 @@ int nes_cm_stop(void)   */  static void cm_event_connected(struct nes_cm_event *event)  { -	u64 u64temp;  	struct nes_qp *nesqp;  	struct nes_vnic *nesvnic;  	struct nes_device *nesdev; @@ -3257,10 +3735,12 @@ static void cm_event_connected(struct nes_cm_event *event)  	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;  	u32 crc_value;  	int ret; +	struct sockaddr_in *laddr; +	struct sockaddr_in *raddr; +	struct sockaddr_in *cm_event_laddr;  	/* get all our handles */  	cm_node = event->cm_node; @@ -3270,32 +3750,26 @@ static void cm_event_connected(struct nes_cm_event *event)  	nesvnic = to_nesvnic(nesqp->ibqp.device);  	nesdev = nesvnic->nesdev;  	nesadapter = nesdev->nesadapter; +	laddr = (struct sockaddr_in *)&cm_id->local_addr; +	raddr = (struct sockaddr_in *)&cm_id->remote_addr; +	cm_event_laddr = (struct sockaddr_in *)&cm_event.local_addr; -	if (nesqp->destroyed) { +	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); +		  " local port 0x%04X. jiffies = %lu.\n", +		  nesqp->hwqp.qp_id, ntohl(raddr->sin_addr.s_addr), +		  ntohs(raddr->sin_port), ntohs(laddr->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)); +			cpu_to_le16(cm_node->mapped_loc_port);  	nesqp->nesqp_context->tcpPorts[1] = -		cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); -	if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) -		nesqp->nesqp_context->ip0 = -			cpu_to_le32(ntohl(nesvnic->local_ipaddr)); -	else -		nesqp->nesqp_context->ip0 = -			cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); +			cpu_to_le16(cm_node->mapped_rem_port); +	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);  	nesqp->nesqp_context->misc2 |= cpu_to_le32(  			(u32)PCI_FUNC(nesdev->pcidev->devfn) << @@ -3310,90 +3784,63 @@ static void cm_event_connected(struct nes_cm_event *event)  	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)cm_node->ord_size);  	/* 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; +	/*nesqp->hwqp.sq_tail = 1;*/ -		if (nesqp->sq_kmapped) { -			nesqp->sq_kmapped = 0; -			kunmap(nesqp->page); -		} +	build_rdma0_msg(cm_node, &nesqp); -		/* 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 +	nes_write32(nesdev->regs + NES_WQE_ALLOC, +		    (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);  	memset(&nes_quad, 0, sizeof(nes_quad));  	nes_quad.DstIpAdrIndex =  		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); -	if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) -		nes_quad.SrcIpadr = nesvnic->local_ipaddr; -	else -		nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; -	nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; -	nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; +	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr); +	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port); +	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);  	/* Produce hash key */  	crc_value = get_crc_value(&nes_quad);  	nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);  	nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n", -			nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask); +		  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; +	nesqp->private_data_len = (u8)cm_node->mpa_frame_size;  	cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);  	/* 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.status = 0;  	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_laddr->sin_family = AF_INET; +	cm_event_laddr->sin_port = laddr->sin_port;  	cm_event.remote_addr = cm_id->remote_addr;  	cm_event.private_data = (void *)event->cm_node->mpa_frame_buf; -	cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size; +	cm_event.private_data_len = (u8)event->cm_node->mpa_frame_size; +	cm_event.ird = cm_node->ird_size; +	cm_event.ord = cm_node->ord_size; -	cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr; +	cm_event_laddr->sin_addr.s_addr = htonl(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(KERN_ERR "%s[%u] OFA CM event_handler returned, " -			"ret=%d\n", __func__, __LINE__, ret); +		       "ret=%d\n", __func__, __LINE__, ret);  	attr.qp_state = IB_QPS_RTS;  	nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);  	nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = " -		"%lu\n", nesqp->hwqp.qp_id, jiffies); +		  "%lu\n", nesqp->hwqp.qp_id, jiffies);  	return;  } @@ -3414,16 +3861,14 @@ static void cm_event_connect_error(struct nes_cm_event *event)  		return;  	cm_id = event->cm_node->cm_id; -	if (!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) { +	if (!nesqp)  		return; -	}  	/* notify OF layer about this connection error event */  	/* cm_id->rem_ref(cm_id); */ @@ -3437,15 +3882,22 @@ static void cm_event_connect_error(struct nes_cm_event *event)  	cm_event.private_data = NULL;  	cm_event.private_data_len = 0; -	nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, " -		"remove_addr=%08x\n", cm_event.local_addr.sin_addr.s_addr, -		cm_event.remote_addr.sin_addr.s_addr); +#ifdef CONFIG_INFINIBAND_NES_DEBUG +	{ +		struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *) +						     &cm_event.local_addr; +		struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *) +						     &cm_event.remote_addr; +		nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remote_addr=%08x\n", +			  cm_event_laddr->sin_addr.s_addr, cm_event_raddr->sin_addr.s_addr); +	} +#endif  	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(KERN_ERR "%s[%u] OFA CM event_handler returned, " -			"ret=%d\n", __func__, __LINE__, ret); +		       "ret=%d\n", __func__, __LINE__, ret);  	cm_id->rem_ref(cm_id);  	rem_ref_cm_node(event->cm_node->cm_core, event->cm_node); @@ -3480,7 +3932,7 @@ static void cm_event_reset(struct nes_cm_event *event)  	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.status = -ECONNRESET;  	cm_event.provider_data = cm_id->provider_data;  	cm_event.local_addr = cm_id->local_addr;  	cm_event.remote_addr = cm_id->remote_addr; @@ -3491,7 +3943,7 @@ static void cm_event_reset(struct nes_cm_event *event)  	ret = cm_id->event_handler(cm_id, &cm_event);  	atomic_inc(&cm_closes);  	cm_event.event = IW_CM_EVENT_CLOSE; -	cm_event.status = IW_CM_EVENT_STATUS_OK; +	cm_event.status = 0;  	cm_event.provider_data = cm_id->provider_data;  	cm_event.local_addr = cm_id->local_addr;  	cm_event.remote_addr = cm_id->remote_addr; @@ -3515,10 +3967,14 @@ static void cm_event_reset(struct nes_cm_event *event)   */  static void cm_event_mpa_req(struct nes_cm_event *event)  { -	struct iw_cm_id   *cm_id; +	struct iw_cm_id *cm_id;  	struct iw_cm_event cm_event;  	int ret;  	struct nes_cm_node *cm_node; +	struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *) +					     &cm_event.local_addr; +	struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *) +					     &cm_event.remote_addr;  	cm_node = event->cm_node;  	if (!cm_node) @@ -3527,36 +3983,47 @@ static void cm_event_mpa_req(struct nes_cm_event *event)  	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_node, cm_id, jiffies);  	cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; -	cm_event.status = IW_CM_EVENT_STATUS_OK; +	cm_event.status = 0;  	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_laddr->sin_family = AF_INET; +	cm_event_laddr->sin_port = htons(event->cm_info.loc_port); +	cm_event_laddr->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_raddr->sin_family = AF_INET; +	cm_event_raddr->sin_port = htons(event->cm_info.rem_port); +	cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);  	cm_event.private_data = cm_node->mpa_frame_buf; -	cm_event.private_data_len  = (u8) cm_node->mpa_frame_size; +	cm_event.private_data_len = (u8)cm_node->mpa_frame_size; +	if (cm_node->mpa_frame_rev == IETF_MPA_V1) { +		cm_event.ird = NES_MAX_IRD; +		cm_event.ord = NES_MAX_ORD; +	} else { +	cm_event.ird = cm_node->ird_size; +	cm_event.ord = cm_node->ord_size; +	}  	ret = cm_id->event_handler(cm_id, &cm_event);  	if (ret)  		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n", -				__func__, __LINE__, ret); +		       __func__, __LINE__, ret);  	return;  }  static void cm_event_mpa_reject(struct nes_cm_event *event)  { -	struct iw_cm_id   *cm_id; +	struct iw_cm_id *cm_id;  	struct iw_cm_event cm_event;  	struct nes_cm_node *cm_node;  	int ret; +	struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *) +					     &cm_event.local_addr; +	struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *) +					     &cm_event.remote_addr;  	cm_node = event->cm_node;  	if (!cm_node) @@ -3565,32 +4032,32 @@ static void cm_event_mpa_reject(struct nes_cm_event *event)  	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_node, cm_id, jiffies);  	cm_event.event = IW_CM_EVENT_CONNECT_REPLY;  	cm_event.status = -ECONNREFUSED;  	cm_event.provider_data = cm_id->provider_data; -	cm_event.local_addr.sin_family = AF_INET; -	cm_event.local_addr.sin_port = htons(event->cm_info.loc_port); -	cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr); +	cm_event_laddr->sin_family = AF_INET; +	cm_event_laddr->sin_port = htons(event->cm_info.loc_port); +	cm_event_laddr->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_raddr->sin_family = AF_INET; +	cm_event_raddr->sin_port = htons(event->cm_info.rem_port); +	cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);  	cm_event.private_data = cm_node->mpa_frame_buf; -	cm_event.private_data_len = (u8) cm_node->mpa_frame_size; +	cm_event.private_data_len = (u8)cm_node->mpa_frame_size;  	nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_REJECTED, local_addr=%08x, " -			"remove_addr=%08x\n", -			cm_event.local_addr.sin_addr.s_addr, -			cm_event.remote_addr.sin_addr.s_addr); +		  "remove_addr=%08x\n", +		  cm_event_laddr->sin_addr.s_addr, +		  cm_event_raddr->sin_addr.s_addr);  	ret = cm_id->event_handler(cm_id, &cm_event);  	if (ret)  		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n", -				__func__, __LINE__, ret); +		       __func__, __LINE__, ret);  	return;  } @@ -3609,7 +4076,7 @@ static int nes_cm_post_event(struct nes_cm_event *event)  	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, "cm_node=%p queue_work, event=%p\n", -		event->cm_node, event); +		  event->cm_node, event);  	queue_work(event->cm_node->cm_core->event_wq, &event->event_work); @@ -3626,7 +4093,7 @@ static int nes_cm_post_event(struct nes_cm_event *event)  static void nes_cm_event_handler(struct work_struct *work)  {  	struct nes_cm_event *event = container_of(work, struct nes_cm_event, -			event_work); +						  event_work);  	struct nes_cm_core *cm_core;  	if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) @@ -3634,29 +4101,29 @@ static void nes_cm_event_handler(struct work_struct *work)  	cm_core = event->cm_node->cm_core;  	nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n", -		event, event->type, atomic_read(&cm_core->events_posted)); +		  event, event->type, atomic_read(&cm_core->events_posted));  	switch (event->type) {  	case NES_CM_EVENT_MPA_REQ:  		cm_event_mpa_req(event);  		nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n", -			event->cm_node); +			  event->cm_node);  		break;  	case NES_CM_EVENT_RESET:  		nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n", -			event->cm_node); +			  event->cm_node);  		cm_event_reset(event);  		break;  	case NES_CM_EVENT_CONNECTED:  		if ((!event->cm_node->cm_id) || -			(event->cm_node->state != NES_CM_STATE_TSA)) +		    (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_MPA_REJECT:  		if ((!event->cm_node->cm_id) || -				(event->cm_node->state == NES_CM_STATE_TSA)) +		    (event->cm_node->state == NES_CM_STATE_TSA))  			break;  		cm_event_mpa_reject(event);  		nes_debug(NES_DBG_CM, "CM Event: REJECT\n"); @@ -3664,7 +4131,7 @@ static void nes_cm_event_handler(struct work_struct *work)  	case NES_CM_EVENT_ABORTED:  		if ((!event->cm_node->cm_id) || -			(event->cm_node->state == NES_CM_STATE_TSA)) +		    (event->cm_node->state == NES_CM_STATE_TSA))  			break;  		cm_event_connect_error(event);  		nes_debug(NES_DBG_CM, "CM Event: ABORTED\n"); diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index d9825fda70a..f522cf63978 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2014 Intel Corporation.  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 @@ -48,7 +48,18 @@  #define IETF_MPA_KEY_SIZE 16  #define IETF_MPA_VERSION  1  #define IETF_MAX_PRIV_DATA_LEN 512 -#define IETF_MPA_FRAME_SIZE     20 +#define IETF_MPA_FRAME_SIZE    20 +#define IETF_RTR_MSG_SIZE      4 +#define IETF_MPA_V2_FLAG       0x10 + +/* IETF RTR MSG Fields               */ +#define IETF_PEER_TO_PEER       0x8000 +#define IETF_FLPDU_ZERO_LEN     0x4000 +#define IETF_RDMA0_WRITE        0x8000 +#define IETF_RDMA0_READ         0x4000 +#define IETF_NO_IRD_ORD         0x3FFF +#define NES_MAX_IRD		 0x40 +#define NES_MAX_ORD		 0x7F  enum ietf_mpa_flags {  	IETF_MPA_FLAGS_MARKERS = 0x80,	/* receive Markers */ @@ -56,7 +67,7 @@ enum ietf_mpa_flags {  	IETF_MPA_FLAGS_REJECT  = 0x20,	/* Reject */  }; -struct ietf_mpa_frame { +struct ietf_mpa_v1 {  	u8 key[IETF_MPA_KEY_SIZE];  	u8 flags;  	u8 rev; @@ -66,6 +77,20 @@ struct ietf_mpa_frame {  #define ietf_mpa_req_resp_frame ietf_mpa_frame +struct ietf_rtr_msg { +	__be16 ctrl_ird; +	__be16 ctrl_ord; +}; + +struct ietf_mpa_v2 { +	u8 key[IETF_MPA_KEY_SIZE]; +	u8 flags; +	u8 rev; +	 __be16 priv_data_len; +	struct ietf_rtr_msg rtr_msg; +	u8 priv_data[0]; +}; +  struct nes_v4_quad {  	u32 rsvd0;  	__le32 DstIpAdrIndex;	/* Only most significant 5 bits are valid */ @@ -171,8 +196,7 @@ struct nes_timer_entry {  #define NES_CM_DEF_SEQ2      0x18ed5740  #define NES_CM_DEF_LOCAL_ID2 0xb807 -#define	MAX_CM_BUFFER	(IETF_MPA_FRAME_SIZE + IETF_MAX_PRIV_DATA_LEN) - +#define	MAX_CM_BUFFER	(IETF_MPA_FRAME_SIZE + IETF_RTR_MSG_SIZE + IETF_MAX_PRIV_DATA_LEN)  typedef u32 nes_addr_t; @@ -204,6 +228,21 @@ enum nes_cm_node_state {  	NES_CM_STATE_CLOSED  }; +enum mpa_frame_version { +	IETF_MPA_V1 = 1, +	IETF_MPA_V2 = 2 +}; + +enum mpa_frame_key { +	MPA_KEY_REQUEST, +	MPA_KEY_REPLY +}; + +enum send_rdma0 { +	SEND_RDMA_READ_ZERO = 1, +	SEND_RDMA_WRITE_ZERO = 2 +}; +  enum nes_tcpip_pkt_type {  	NES_PKT_TYPE_UNKNOWN,  	NES_PKT_TYPE_SYN, @@ -245,17 +284,17 @@ struct nes_cm_tcp_context {  enum nes_cm_listener_state { -	NES_CM_LISTENER_PASSIVE_STATE=1, -	NES_CM_LISTENER_ACTIVE_STATE=2, -	NES_CM_LISTENER_EITHER_STATE=3 +	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;  	struct nes_cm_core         *cm_core;  	u8                         loc_mac[ETH_ALEN]; -	nes_addr_t                 loc_addr; -	u16                        loc_port; +	nes_addr_t                 loc_addr, mapped_loc_addr; +	u16                        loc_port, mapped_loc_port;  	struct iw_cm_id            *cm_id;  	enum nes_cm_conn_type      conn_type;  	atomic_t                   ref_count; @@ -269,7 +308,9 @@ struct nes_cm_listener {  /* per connection node and node state information */  struct nes_cm_node {  	nes_addr_t                loc_addr, rem_addr; +	nes_addr_t                mapped_loc_addr, mapped_rem_addr;  	u16                       loc_port, rem_port; +	u16                       mapped_loc_port, mapped_rem_port;  	u8                        loc_mac[ETH_ALEN];  	u8                        rem_mac[ETH_ALEN]; @@ -283,16 +324,21 @@ struct nes_cm_node {  	struct nes_cm_node        *loopbackpartner; -	struct nes_timer_entry	*send_entry; - +	struct nes_timer_entry	  *send_entry; +	struct nes_timer_entry    *recv_entry;  	spinlock_t                retrans_list_lock; -	struct nes_timer_entry  *recv_entry; +	enum send_rdma0           send_rdma0_op; -	int                       send_write0;  	union { -		struct ietf_mpa_frame mpa_frame; -		u8                    mpa_frame_buf[MAX_CM_BUFFER]; +		struct ietf_mpa_v1 mpa_frame; +		struct ietf_mpa_v2 mpa_v2_frame; +		u8                 mpa_frame_buf[MAX_CM_BUFFER];  	}; +	enum mpa_frame_version    mpa_frame_rev; +	u16			  ird_size; +	u16                       ord_size; +	u16			  mpav2_ird_ord; +  	u16                       mpa_frame_size;  	struct iw_cm_id           *cm_id;  	struct list_head          list; @@ -320,6 +366,10 @@ struct nes_cm_info {  	u16 rem_port;  	nes_addr_t loc_addr;  	nes_addr_t rem_addr; +	u16 mapped_loc_port; +	u16 mapped_rem_port; +	nes_addr_t mapped_loc_addr; +	nes_addr_t mapped_rem_addr;  	enum nes_cm_conn_type  conn_type;  	int backlog; @@ -399,10 +449,8 @@ struct nes_cm_ops {  			struct nes_vnic *, u16, void *,  			struct nes_cm_info *);  	int (*close)(struct nes_cm_core *, struct nes_cm_node *); -	int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *, -			struct nes_cm_node *); -	int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *, -			struct nes_cm_node *); +	int (*accept)(struct nes_cm_core *, struct nes_cm_node *); +	int (*reject)(struct nes_cm_core *, 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 *); @@ -422,5 +470,7 @@ 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); +int nes_add_ref_cm_node(struct nes_cm_node *cm_node); +int nes_rem_ref_cm_node(struct nes_cm_node *cm_node);  #endif			/* NES_CM_H */ diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h index b4393a16099..a69eef16d72 100644 --- a/drivers/infiniband/hw/nes/nes_context.h +++ b/drivers/infiniband/hw/nes/nes_context.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 1980a461c49..90200245c5e 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -75,12 +75,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,  static void process_critical_error(struct nes_device *nesdev);  static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);  static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); -static void nes_terminate_timeout(unsigned long context);  static void nes_terminate_start_timer(struct nes_qp *nesqp);  #ifdef CONFIG_INFINIBAND_NES_DEBUG  static unsigned char *nes_iwarp_state_str[] = { -	"Non-Existant", +	"Non-Existent",  	"Idle",  	"RTS",  	"Closing", @@ -91,7 +90,7 @@ static unsigned char *nes_iwarp_state_str[] = {  };  static unsigned char *nes_tcp_state_str[] = { -	"Non-Existant", +	"Non-Existent",  	"Closed",  	"Listen",  	"SYN Sent", @@ -110,6 +109,14 @@ static unsigned char *nes_tcp_state_str[] = {  };  #endif +static inline void print_ip(struct nes_cm_node *cm_node) +{ +	unsigned char *rem_addr; +	if (cm_node) { +		rem_addr = (unsigned char *)&cm_node->rem_addr; +		printk(KERN_ERR PFX "Remote IP addr: %pI4\n", rem_addr); +	} +}  /**   * nes_nic_init_timer_defaults @@ -1521,7 +1528,7 @@ int nes_init_phy(struct nes_device *nesdev)  	} else {  		/* setup 10G MDIO operation */  		tx_config &= 0xFFFFFFE3; -		tx_config |= 0x15; +		tx_config |= 0x1D;  	}  	nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); @@ -1555,6 +1562,7 @@ static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)  	struct nes_hw_nic_rq_wqe *nic_rqe;  	struct nes_hw_nic *nesnic;  	struct nes_device *nesdev; +	struct nes_rskb_cb *cb;  	u32 rx_wqes_posted = 0;  	nesnic = &nesvnic->nic; @@ -1580,6 +1588,9 @@ static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)  			bus_address = pci_map_single(nesdev->pcidev,  					skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); +			cb = (struct nes_rskb_cb *)&skb->cb[0]; +			cb->busaddr = bus_address; +			cb->maplen = nesvnic->max_frame_size;  			nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];  			nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = @@ -1669,6 +1680,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)  	u32 cqp_head;  	u32 counter;  	u32 wqe_count; +	struct nes_rskb_cb *cb;  	u8 jumbomode=0;  	/* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */ @@ -1845,6 +1857,9 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)  		pmem = pci_map_single(nesdev->pcidev, skb->data,  				nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); +		cb = (struct nes_rskb_cb *)&skb->cb[0]; +		cb->busaddr = pmem; +		cb->maplen = nesvnic->max_frame_size;  		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); @@ -1873,6 +1888,13 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)  			jumbomode = 1;  		nes_nic_init_timer_defaults(nesdev, jumbomode);  	} +	if ((nesdev->nesadapter->allow_unaligned_fpdus) && +		(nes_init_mgt_qp(nesdev, netdev, nesvnic))) { +			nes_debug(NES_DBG_INIT, "%s: Out of memory for pau nic\n", netdev->name); +			nes_destroy_nic_qp(nesvnic); +		return -ENOMEM; +	} +  	nesvnic->lro_mgr.max_aggr       = nes_lro_max_aggr;  	nesvnic->lro_mgr.max_desc       = NES_MAX_LRO_DESCRIPTORS;  	nesvnic->lro_mgr.lro_arr        = nesvnic->lro_desc; @@ -1895,28 +1917,29 @@ 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_sq_wqe *nic_sqe; -	struct nes_hw_nic_rq_wqe *nic_rqe;  	__le16 *wqe_fragment_length;  	u16  wqe_fragment_index; -	u64 wqe_frag;  	u32 cqp_head;  	u32 wqm_cfg0;  	unsigned long flags; +	struct sk_buff *rx_skb; +	struct nes_rskb_cb *cb;  	int ret; +	if (nesdev->nesadapter->allow_unaligned_fpdus) +		nes_destroy_mgt(nesvnic); +  	/* clear wqe stall before destroying NIC QP */  	wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0);  	nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF);  	/* 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); +		rx_skb = nesvnic->nic.rx_skb[nesvnic->nic.rq_tail]; +		cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; +		pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, +			PCI_DMA_FROMDEVICE); +  		dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);  		nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);  	} @@ -2608,6 +2631,15 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)  						netif_start_queue(nesvnic->netdev);  					nesvnic->linkup = 1;  					netif_carrier_on(nesvnic->netdev); + +					spin_lock(&nesvnic->port_ibevent_lock); +					if (nesvnic->of_device_registered) { +						if (nesdev->iw_status == 0) { +							nesdev->iw_status = 1; +							nes_port_ibevent(nesvnic); +						} +					} +					spin_unlock(&nesvnic->port_ibevent_lock);  				}  			}  		} else { @@ -2633,9 +2665,23 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)  						netif_stop_queue(nesvnic->netdev);  					nesvnic->linkup = 0;  					netif_carrier_off(nesvnic->netdev); + +					spin_lock(&nesvnic->port_ibevent_lock); +					if (nesvnic->of_device_registered) { +						if (nesdev->iw_status == 1) { +							nesdev->iw_status = 0; +							nes_port_ibevent(nesvnic); +						} +					} +					spin_unlock(&nesvnic->port_ibevent_lock);  				}  			}  		} +		if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) { +			nesdev->link_recheck = 1; +			mod_delayed_work(system_wq, &nesdev->work, +					 NES_LINK_RECHECK_DELAY); +		}  	}  	spin_unlock_irqrestore(&nesadapter->phy_lock, flags); @@ -2643,6 +2689,84 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)  	nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;  } +void nes_recheck_link_status(struct work_struct *work) +{ +	unsigned long flags; +	struct nes_device *nesdev = container_of(work, struct nes_device, work.work); +	struct nes_adapter *nesadapter = nesdev->nesadapter; +	struct nes_vnic *nesvnic; +	u32 mac_index = nesdev->mac_index; +	u16 phy_data; +	u16 temp_phy_data; + +	spin_lock_irqsave(&nesadapter->phy_lock, flags); + +	/* check link status */ +	nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); +	temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + +	nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); +	nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); +	nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); +	phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + +	phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; + +	nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", +		__func__, phy_data, +		nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); + +	if (phy_data & 0x0004) { +		nesadapter->mac_link_down[mac_index] = 0; +		list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { +			if (nesvnic->linkup == 0) { +				printk(PFX "The Link is now up for port %s, netdev %p.\n", +						nesvnic->netdev->name, nesvnic->netdev); +				if (netif_queue_stopped(nesvnic->netdev)) +					netif_start_queue(nesvnic->netdev); +				nesvnic->linkup = 1; +				netif_carrier_on(nesvnic->netdev); + +				spin_lock(&nesvnic->port_ibevent_lock); +				if (nesvnic->of_device_registered) { +					if (nesdev->iw_status == 0) { +						nesdev->iw_status = 1; +						nes_port_ibevent(nesvnic); +					} +				} +				spin_unlock(&nesvnic->port_ibevent_lock); +			} +		} + +	} else { +		nesadapter->mac_link_down[mac_index] = 1; +		list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { +			if (nesvnic->linkup == 1) { +				printk(PFX "The Link is now down for port %s, netdev %p.\n", +						nesvnic->netdev->name, nesvnic->netdev); +				if (!(netif_queue_stopped(nesvnic->netdev))) +					netif_stop_queue(nesvnic->netdev); +				nesvnic->linkup = 0; +				netif_carrier_off(nesvnic->netdev); + +				spin_lock(&nesvnic->port_ibevent_lock); +				if (nesvnic->of_device_registered) { +					if (nesdev->iw_status == 1) { +						nesdev->iw_status = 0; +						nes_port_ibevent(nesvnic); +					} +				} +				spin_unlock(&nesvnic->port_ibevent_lock); +			} +		} +	} +	if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX) +		schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); +	else +		nesdev->link_recheck = 0; + +	spin_unlock_irqrestore(&nesadapter->phy_lock, flags); +}  static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) @@ -2672,6 +2796,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)  	struct nes_hw_nic_sq_wqe *nic_sqe;  	struct sk_buff *skb;  	struct sk_buff *rx_skb; +	struct nes_rskb_cb *cb;  	__le16 *wqe_fragment_length;  	u32 head;  	u32 cq_size; @@ -2756,6 +2881,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)  				bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;  				pci_unmap_single(nesdev->pcidev, bus_address,  						nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); +				cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; +				cb->busaddr = 0;  				/* rx_skb->tail = rx_skb->data + rx_pkt_size; */  				/* rx_skb->len = rx_pkt_size; */  				rx_skb->len = 0;  /* TODO: see if this is necessary */ @@ -2782,9 +2909,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)  					if ((cqe_errv &  							(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |  							NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { -						if (nesvnic->rx_checksum_disabled == 0) { +						if (nesvnic->netdev->features & NETIF_F_RXCSUM)  							rx_skb->ip_summed = CHECKSUM_UNNECESSARY; -						}  					} else  						nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."  								" errv = 0x%X, pkt_type = 0x%X.\n", @@ -2794,7 +2920,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)  					if ((cqe_errv &  							(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |  							NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { -						if (nesvnic->rx_checksum_disabled == 0) { +						if (nesvnic->netdev->features & NETIF_F_RXCSUM) {  							rx_skb->ip_summed = CHECKSUM_UNNECESSARY;  							/* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",  								  nesvnic->netdev->name); */ @@ -2815,24 +2941,19 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)  					goto skip_rx_indicate0; -				if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && -				    (nesvnic->vlan_grp != NULL)) { +				if (cqe_misc & NES_NIC_CQE_TAG_VALID) {  					vlan_tag = (u16)(le32_to_cpu(  							cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])  							>> 16);  					nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",  							nesvnic->netdev->name, vlan_tag); -					if (nes_use_lro) -						lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, -								nesvnic->vlan_grp, vlan_tag, NULL); -					else -						nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); -				} else { -					if (nes_use_lro) -						lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); -					else -						nes_netif_rx(rx_skb); + +					__vlan_hwaccel_put_tag(rx_skb, htons(ETH_P_8021Q), vlan_tag);  				} +				if (nes_use_lro) +					lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); +				else +					netif_receive_skb(rx_skb);  skip_rx_indicate0:  				; @@ -2886,6 +3007,7 @@ skip_rx_indicate0:  } +  /**   * nes_cqp_ce_handler   */ @@ -2900,6 +3022,8 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)  	u32 cq_size;  	u32 cqe_count=0;  	u32 error_code; +	u32 opcode; +	u32 ctx_index;  	/* u32 counter; */  	head = cq->cq_head; @@ -2910,12 +3034,9 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)  		/* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head,  			  le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */ -		if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { -			u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. -					cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | -					((u64)(le32_to_cpu(cq->cq_vbase[head]. -					cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); -			cqp = *((struct nes_hw_cqp **)&u64temp); +		opcode = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]); +		if (opcode & NES_CQE_VALID) { +			cqp = &nesdev->cqp;  			error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);  			if (error_code) { @@ -2924,15 +3045,14 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)  						le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,  						(u16)(error_code >> 16),  						(u16)error_code); -				nes_debug(NES_DBG_CQP, "cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n", -						cqp->qp_id, cqp->sq_head, cqp->sq_tail);  			} -			u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. -					wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | -					((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. -					wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]))); -			cqp_request = *((struct nes_cqp_request **)&u64temp); +			u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. +					cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | +					((u64)(le32_to_cpu(cq->cq_vbase[head]. +					cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); + +			cqp_request = (struct nes_cqp_request *)(unsigned long)u64temp;  			if (cqp_request) {  				if (cqp_request->waiting) {  					/* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */ @@ -2978,9 +3098,15 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)  		cqp_wqe = &nesdev->cqp.sq_vbase[head];  		memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));  		barrier(); -		cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = + +		opcode = cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]; +		if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT) +			ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX; +		else +			ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX; +		cqp_wqe->wqe_words[ctx_index] =  			cpu_to_le32((u32)((unsigned long)cqp_request)); -		cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = +		cqp_wqe->wqe_words[ctx_index + 1] =  			cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request)));  		nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n",  				cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head); @@ -2996,7 +3122,6 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)  	nes_read32(nesdev->regs+NES_CQE_ALLOC);  } -  static u8 *locate_mpa(u8 *pkt, u32 aeq_info)  {  	if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { @@ -3394,7 +3519,7 @@ static void nes_terminate_received(struct nes_device *nesdev,  }  /* Timeout routine in case terminate fails to complete */ -static void nes_terminate_timeout(unsigned long context) +void nes_terminate_timeout(unsigned long context)  {  	struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; @@ -3404,11 +3529,7 @@ static void nes_terminate_timeout(unsigned long context)  /* Set a timer in case hw cannot complete the terminate sequence */  static void nes_terminate_start_timer(struct nes_qp *nesqp)  { -	init_timer(&nesqp->terminate_timer); -	nesqp->terminate_timer.function = nes_terminate_timeout; -	nesqp->terminate_timer.expires = jiffies + HZ; -	nesqp->terminate_timer.data = (unsigned long)nesqp; -	add_timer(&nesqp->terminate_timer); +	mod_timer(&nesqp->terminate_timer, (jiffies + HZ));  }  /** @@ -3456,9 +3577,9 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,  	aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);  	if (aeq_info & NES_AEQE_QP) { -		if ((!nes_is_resource_allocated(nesadapter, nesadapter->allocated_qps, -				aeqe_cq_id)) || -				(atomic_read(&nesqp->close_timer_started))) +		if (!nes_is_resource_allocated(nesadapter, +				nesadapter->allocated_qps, +				aeqe_cq_id))  			return;  	} @@ -3469,8 +3590,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,  			if (atomic_inc_return(&nesqp->close_timer_started) == 1) {  				if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) && -					(nesqp->ibqp_state == IB_QPS_RTS) && -					((nesadapter->eeprom_version >> 16) != NES_A0)) { +					(nesqp->ibqp_state == IB_QPS_RTS)) {  					spin_lock_irqsave(&nesqp->lock, flags);  					nesqp->hw_iwarp_state = iwarp_state;  					nesqp->hw_tcp_state = tcp_state; @@ -3492,14 +3612,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,  			}  			break;  		case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: -			if (nesqp->term_flags) { -				nes_terminate_done(nesqp, 0); -				return; -			}  			spin_lock_irqsave(&nesqp->lock, flags); -			nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; +			nesqp->hw_iwarp_state = iwarp_state; +			nesqp->hw_tcp_state = tcp_state; +			nesqp->last_aeq = async_event_id;  			spin_unlock_irqrestore(&nesqp->lock, flags); -			nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_CLOSING, 0, 0);  			nes_cm_disconn(nesqp);  			break; @@ -3597,7 +3714,9 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,  		case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:  			printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_FATAL\n",  					nesqp->hwqp.qp_id, async_event_id); -			nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); +			print_ip(nesqp->cm_node); +			if (!atomic_read(&nesqp->close_timer_started)) +				nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);  			break;  		case NES_AEQE_AEID_CQ_OPERATION_ERROR: diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 1204c3432b6..d748e4b31b8 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1,5 +1,5 @@  /* -* Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. +* Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -47,6 +47,11 @@  #define NES_MULTICAST_PF_MAX 8  #define NES_A0 3 +#define NES_ENABLE_PAU 0x07000001 +#define NES_DISABLE_PAU 0x07000000 +#define NES_PAU_COUNTER 10 +#define NES_CQP_OPCODE_MASK 0x3f +  enum pci_regs {  	NES_INT_STAT = 0x0000,  	NES_INT_MASK = 0x0004, @@ -73,8 +78,10 @@ enum indexed_regs {  	NES_IDX_QP_CONTROL = 0x0040,  	NES_IDX_FLM_CONTROL = 0x0080,  	NES_IDX_INT_CPU_STATUS = 0x00a0, +	NES_IDX_GPR_TRIGGER = 0x00bc,  	NES_IDX_GPIO_CONTROL = 0x00f0,  	NES_IDX_GPIO_DATA = 0x00f4, +	NES_IDX_GPR2 = 0x010c,  	NES_IDX_TCP_CONFIG0 = 0x01e4,  	NES_IDX_TCP_TIMER_CONFIG = 0x01ec,  	NES_IDX_TCP_NOW = 0x01f0, @@ -202,6 +209,7 @@ enum nes_cqp_opcodes {  	NES_CQP_REGISTER_SHARED_STAG = 0x0c,  	NES_CQP_DEALLOCATE_STAG = 0x0d,  	NES_CQP_MANAGE_ARP_CACHE = 0x0f, +	NES_CQP_DOWNLOAD_SEGMENT = 0x10,  	NES_CQP_SUSPEND_QPS = 0x11,  	NES_CQP_UPLOAD_CONTEXT = 0x13,  	NES_CQP_CREATE_CEQ = 0x16, @@ -210,7 +218,8 @@ enum nes_cqp_opcodes {  	NES_CQP_DESTROY_AEQ = 0x1b,  	NES_CQP_LMI_ACCESS = 0x20,  	NES_CQP_FLUSH_WQES = 0x22, -	NES_CQP_MANAGE_APBVT = 0x23 +	NES_CQP_MANAGE_APBVT = 0x23, +	NES_CQP_MANAGE_QUAD_HASH = 0x25  };  enum nes_cqp_wqe_word_idx { @@ -222,6 +231,14 @@ enum nes_cqp_wqe_word_idx {  	NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5,  }; +enum nes_cqp_wqe_word_download_idx { /* format differs from other cqp ops */ +	NES_CQP_WQE_DL_OPCODE_IDX = 0, +	NES_CQP_WQE_DL_COMP_CTX_LOW_IDX = 1, +	NES_CQP_WQE_DL_COMP_CTX_HIGH_IDX = 2, +	NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX = 3 +	/* For index values 4-15 use NES_NIC_SQ_WQE_ values */ +}; +  enum nes_cqp_cq_wqeword_idx {  	NES_CQP_CQ_WQE_PBL_LOW_IDX = 6,  	NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7, @@ -242,6 +259,7 @@ enum nes_cqp_stag_wqeword_idx {  	NES_CQP_STAG_WQE_PBL_LEN_IDX = 14  }; +#define NES_CQP_OP_LOGICAL_PORT_SHIFT 26  #define NES_CQP_OP_IWARP_STATE_SHIFT 28  #define NES_CQP_OP_TERMLEN_SHIFT     28 @@ -599,6 +617,7 @@ enum nes_nic_sq_wqe_bits {  enum nes_nic_cqe_word_idx {  	NES_NIC_CQE_ACCQP_ID_IDX = 0, +	NES_NIC_CQE_HASH_RCVNXT = 1,  	NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2,  	NES_NIC_CQE_MISC_IDX = 3,  }; @@ -1005,6 +1024,11 @@ struct nes_arp_entry {  #define NES_NIC_CQ_DOWNWARD_TREND   16  #define NES_PFT_SIZE		    48 +#define NES_MGT_WQ_COUNT 32 +#define NES_MGT_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_32) | (NES_NIC_CTX_SQ_SIZE_32)) +#define NES_MGT_QP_OFFSET 36 +#define NES_MGT_QP_COUNT 4 +  struct nes_hw_tune_timer {      /* u16 cq_count; */      u16 threshold_low; @@ -1118,6 +1142,7 @@ struct nes_adapter {  	u32 et_rate_sample_interval;  	u32 timer_int_limit;  	u32 wqm_quanta; +	u8 allow_unaligned_fpdus;  	/* Adapter base MAC address */  	u32 mac_addr_low; @@ -1193,6 +1218,8 @@ struct nes_listener {  struct nes_ib_device; +#define NES_EVENT_DELAY msecs_to_jiffies(100) +  struct nes_vnic {  	struct nes_ib_device *nesibdev;  	u64 sq_full; @@ -1209,7 +1236,6 @@ struct nes_vnic {  	/* void *mem; */  	struct nes_device *nesdev;  	struct net_device *netdev; -	struct vlan_group *vlan_grp;  	atomic_t          rx_skbs_needed;  	atomic_t          rx_skb_timer_running;  	int               budget; @@ -1243,10 +1269,21 @@ struct nes_vnic {  	u8  next_qp_nic_index;  	u8  of_device_registered;  	u8  rdma_enabled; -	u8  rx_checksum_disabled;  	u32 lro_max_aggr;  	struct net_lro_mgr lro_mgr;  	struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; +	struct timer_list event_timer; +	enum ib_event_type delayed_event; +	enum ib_event_type last_dispatched_event; +	spinlock_t port_ibevent_lock; +	u32 mgt_mem_size; +	void *mgt_vbase; +	dma_addr_t mgt_pbase; +	struct nes_vnic_mgt *mgtvnic[NES_MGT_QP_COUNT]; +	struct task_struct *mgt_thread; +	wait_queue_head_t mgt_wait_queue; +	struct sk_buff_head mgt_skb_list; +  };  struct nes_ib_device { @@ -1348,7 +1385,8 @@ struct nes_terminate_hdr {  #define BAD_FRAME_OFFSET	64  #define CQE_MAJOR_DRV		0x8000 -#define nes_vlan_rx vlan_hwaccel_receive_skb -#define nes_netif_rx netif_receive_skb +/* Used for link status recheck after interrupt processing */ +#define NES_LINK_RECHECK_DELAY	msecs_to_jiffies(50) +#define NES_LINK_RECHECK_MAX	60  #endif		/* __NES_HW_H */ diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c new file mode 100644 index 00000000000..416645259b0 --- /dev/null +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -0,0 +1,1160 @@ +/* + * Copyright (c) 2006 - 2011 Intel-NE, Inc.  All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * 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/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/kthread.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <net/tcp.h> +#include "nes.h" +#include "nes_mgt.h" + +atomic_t pau_qps_created; +atomic_t pau_qps_destroyed; + +static void nes_replenish_mgt_rq(struct nes_vnic_mgt *mgtvnic) +{ +	unsigned long flags; +	dma_addr_t bus_address; +	struct sk_buff *skb; +	struct nes_hw_nic_rq_wqe *nic_rqe; +	struct nes_hw_mgt *nesmgt; +	struct nes_device *nesdev; +	struct nes_rskb_cb *cb; +	u32 rx_wqes_posted = 0; + +	nesmgt = &mgtvnic->mgt; +	nesdev = mgtvnic->nesvnic->nesdev; +	spin_lock_irqsave(&nesmgt->rq_lock, flags); +	if (nesmgt->replenishing_rq != 0) { +		if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) && +		    (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) { +			atomic_set(&mgtvnic->rx_skb_timer_running, 1); +			spin_unlock_irqrestore(&nesmgt->rq_lock, flags); +			mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2);      /* 1/2 second */ +			add_timer(&mgtvnic->rq_wqes_timer); +		} else { +			spin_unlock_irqrestore(&nesmgt->rq_lock, flags); +		} +		return; +	} +	nesmgt->replenishing_rq = 1; +	spin_unlock_irqrestore(&nesmgt->rq_lock, flags); +	do { +		skb = dev_alloc_skb(mgtvnic->nesvnic->max_frame_size); +		if (skb) { +			skb->dev = mgtvnic->nesvnic->netdev; + +			bus_address = pci_map_single(nesdev->pcidev, +						     skb->data, mgtvnic->nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); +			cb = (struct nes_rskb_cb *)&skb->cb[0]; +			cb->busaddr = bus_address; +			cb->maplen = mgtvnic->nesvnic->max_frame_size; + +			nic_rqe = &nesmgt->rq_vbase[mgtvnic->mgt.rq_head]; +			nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = +				cpu_to_le32(mgtvnic->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)); +			nesmgt->rx_skb[nesmgt->rq_head] = skb; +			nesmgt->rq_head++; +			nesmgt->rq_head &= nesmgt->rq_size - 1; +			atomic_dec(&mgtvnic->rx_skbs_needed); +			barrier(); +			if (++rx_wqes_posted == 255) { +				nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id); +				rx_wqes_posted = 0; +			} +		} else { +			spin_lock_irqsave(&nesmgt->rq_lock, flags); +			if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) && +			    (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) { +				atomic_set(&mgtvnic->rx_skb_timer_running, 1); +				spin_unlock_irqrestore(&nesmgt->rq_lock, flags); +				mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2);      /* 1/2 second */ +				add_timer(&mgtvnic->rq_wqes_timer); +			} else { +				spin_unlock_irqrestore(&nesmgt->rq_lock, flags); +			} +			break; +		} +	} while (atomic_read(&mgtvnic->rx_skbs_needed)); +	barrier(); +	if (rx_wqes_posted) +		nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id); +	nesmgt->replenishing_rq = 0; +} + +/** + * nes_mgt_rq_wqes_timeout + */ +static void nes_mgt_rq_wqes_timeout(unsigned long parm) +{ +	struct nes_vnic_mgt *mgtvnic = (struct nes_vnic_mgt *)parm; + +	atomic_set(&mgtvnic->rx_skb_timer_running, 0); +	if (atomic_read(&mgtvnic->rx_skbs_needed)) +		nes_replenish_mgt_rq(mgtvnic); +} + +/** + * nes_mgt_free_skb - unmap and free skb + */ +static void nes_mgt_free_skb(struct nes_device *nesdev, struct sk_buff *skb, u32 dir) +{ +	struct nes_rskb_cb *cb; + +	cb = (struct nes_rskb_cb *)&skb->cb[0]; +	pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, dir); +	cb->busaddr = 0; +	dev_kfree_skb_any(skb); +} + +/** + * nes_download_callback - handle download completions + */ +static void nes_download_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request) +{ +	struct pau_fpdu_info *fpdu_info = cqp_request->cqp_callback_pointer; +	struct nes_qp *nesqp = fpdu_info->nesqp; +	struct sk_buff *skb; +	int i; + +	for (i = 0; i < fpdu_info->frag_cnt; i++) { +		skb = fpdu_info->frags[i].skb; +		if (fpdu_info->frags[i].cmplt) { +			nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE); +			nes_rem_ref_cm_node(nesqp->cm_node); +		} +	} + +	if (fpdu_info->hdr_vbase) +		pci_free_consistent(nesdev->pcidev, fpdu_info->hdr_len, +				    fpdu_info->hdr_vbase, fpdu_info->hdr_pbase); +	kfree(fpdu_info); +} + +/** + * nes_get_seq - Get the seq, ack_seq and window from the packet + */ +static u32 nes_get_seq(struct sk_buff *skb, u32 *ack, u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd) +{ +	struct nes_rskb_cb *cb = (struct nes_rskb_cb *)&skb->cb[0]; +	struct iphdr *iph = (struct iphdr *)(cb->data_start + ETH_HLEN); +	struct tcphdr *tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); + +	*ack = be32_to_cpu(tcph->ack_seq); +	*wnd = be16_to_cpu(tcph->window); +	*fin_rcvd = tcph->fin; +	*rst_rcvd = tcph->rst; +	return be32_to_cpu(tcph->seq); +} + +/** + * nes_get_next_skb - Get the next skb based on where current skb is in the queue + */ +static struct sk_buff *nes_get_next_skb(struct nes_device *nesdev, struct nes_qp *nesqp, +					struct sk_buff *skb, u32 nextseq, u32 *ack, +					u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd) +{ +	u32 seq; +	bool processacks; +	struct sk_buff *old_skb; + +	if (skb) { +		/* Continue processing fpdu */ +		if (skb->next == (struct sk_buff *)&nesqp->pau_list) +			goto out; +		skb = skb->next; +		processacks = false; +	} else { +		/* Starting a new one */ +		if (skb_queue_empty(&nesqp->pau_list)) +			goto out; +		skb = skb_peek(&nesqp->pau_list); +		processacks = true; +	} + +	while (1) { +		if (skb_queue_empty(&nesqp->pau_list)) +			goto out; + +		seq = nes_get_seq(skb, ack, wnd, fin_rcvd, rst_rcvd); +		if (seq == nextseq) { +			if (skb->len || processacks) +				break; +		} else if (after(seq, nextseq)) { +			goto out; +		} + +		old_skb = skb; +		skb = skb->next; +		skb_unlink(old_skb, &nesqp->pau_list); +		nes_mgt_free_skb(nesdev, old_skb, PCI_DMA_TODEVICE); +		nes_rem_ref_cm_node(nesqp->cm_node); +		if (skb == (struct sk_buff *)&nesqp->pau_list) +			goto out; +	} +	return skb; + +out: +	return NULL; +} + +/** + * get_fpdu_info - Find the next complete fpdu and return its fragments. + */ +static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp, +			 struct pau_fpdu_info **pau_fpdu_info) +{ +	struct sk_buff *skb; +	struct iphdr *iph; +	struct tcphdr *tcph; +	struct nes_rskb_cb *cb; +	struct pau_fpdu_info *fpdu_info = NULL; +	struct pau_fpdu_frag frags[MAX_FPDU_FRAGS]; +	u32 fpdu_len = 0; +	u32 tmp_len; +	int frag_cnt = 0; +	u32 tot_len; +	u32 frag_tot; +	u32 ack; +	u32 fin_rcvd; +	u32 rst_rcvd; +	u16 wnd; +	int i; +	int rc = 0; + +	*pau_fpdu_info = NULL; + +	skb = nes_get_next_skb(nesdev, nesqp, NULL, nesqp->pau_rcv_nxt, &ack, &wnd, &fin_rcvd, &rst_rcvd); +	if (!skb) +		goto out; + +	cb = (struct nes_rskb_cb *)&skb->cb[0]; +	if (skb->len) { +		fpdu_len = be16_to_cpu(*(__be16 *) skb->data) + MPA_FRAMING; +		fpdu_len = (fpdu_len + 3) & 0xfffffffc; +		tmp_len = fpdu_len; + +		/* See if we have all of the fpdu */ +		frag_tot = 0; +		memset(&frags, 0, sizeof frags); +		for (i = 0; i < MAX_FPDU_FRAGS; i++) { +			frags[i].physaddr = cb->busaddr; +			frags[i].physaddr += skb->data - cb->data_start; +			frags[i].frag_len = min(tmp_len, skb->len); +			frags[i].skb = skb; +			frags[i].cmplt = (skb->len == frags[i].frag_len); +			frag_tot += frags[i].frag_len; +			frag_cnt++; + +			tmp_len -= frags[i].frag_len; +			if (tmp_len == 0) +				break; + +			skb = nes_get_next_skb(nesdev, nesqp, skb, +					       nesqp->pau_rcv_nxt + frag_tot, &ack, &wnd, &fin_rcvd, &rst_rcvd); +			if (!skb) +				goto out; +			if (rst_rcvd) { +				/* rst received in the middle of fpdu */ +				for (; i >= 0; i--) { +					skb_unlink(frags[i].skb, &nesqp->pau_list); +					nes_mgt_free_skb(nesdev, frags[i].skb, PCI_DMA_TODEVICE); +				} +				cb = (struct nes_rskb_cb *)&skb->cb[0]; +				frags[0].physaddr = cb->busaddr; +				frags[0].physaddr += skb->data - cb->data_start; +				frags[0].frag_len = skb->len; +				frags[0].skb = skb; +				frags[0].cmplt = true; +				frag_cnt = 1; +				break; +			} + +			cb = (struct nes_rskb_cb *)&skb->cb[0]; +		} +	} else { +		/* no data */ +		frags[0].physaddr = cb->busaddr; +		frags[0].frag_len = 0; +		frags[0].skb = skb; +		frags[0].cmplt = true; +		frag_cnt = 1; +	} + +	/* Found one */ +	fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC); +	if (fpdu_info == NULL) { +		nes_debug(NES_DBG_PAU, "Failed to alloc a fpdu_info.\n"); +		rc = -ENOMEM; +		goto out; +	} + +	fpdu_info->cqp_request = nes_get_cqp_request(nesdev); +	if (fpdu_info->cqp_request == NULL) { +		nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); +		rc = -ENOMEM; +		goto out; +	} + +	cb = (struct nes_rskb_cb *)&frags[0].skb->cb[0]; +	iph = (struct iphdr *)(cb->data_start + ETH_HLEN); +	tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); +	fpdu_info->hdr_len = (((unsigned char *)tcph) + 4 * (tcph->doff)) - cb->data_start; +	fpdu_info->data_len = fpdu_len; +	tot_len = fpdu_info->hdr_len + fpdu_len - ETH_HLEN; + +	if (frags[0].cmplt) { +		fpdu_info->hdr_pbase = cb->busaddr; +		fpdu_info->hdr_vbase = NULL; +	} else { +		fpdu_info->hdr_vbase = pci_alloc_consistent(nesdev->pcidev, +							    fpdu_info->hdr_len, &fpdu_info->hdr_pbase); +		if (!fpdu_info->hdr_vbase) { +			nes_debug(NES_DBG_PAU, "Unable to allocate memory for pau first frag\n"); +			rc = -ENOMEM; +			goto out; +		} + +		/* Copy hdrs, adjusting len and seqnum */ +		memcpy(fpdu_info->hdr_vbase, cb->data_start, fpdu_info->hdr_len); +		iph = (struct iphdr *)(fpdu_info->hdr_vbase + ETH_HLEN); +		tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); +	} + +	iph->tot_len = cpu_to_be16(tot_len); +	iph->saddr = cpu_to_be32(0x7f000001); + +	tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt); +	tcph->ack_seq = cpu_to_be32(ack); +	tcph->window = cpu_to_be16(wnd); + +	nesqp->pau_rcv_nxt += fpdu_len + fin_rcvd; + +	memcpy(fpdu_info->frags, frags, sizeof(fpdu_info->frags)); +	fpdu_info->frag_cnt = frag_cnt; +	fpdu_info->nesqp = nesqp; +	*pau_fpdu_info = fpdu_info; + +	/* Update skb's for next pass */ +	for (i = 0; i < frag_cnt; i++) { +		cb = (struct nes_rskb_cb *)&frags[i].skb->cb[0]; +		skb_pull(frags[i].skb, frags[i].frag_len); + +		if (frags[i].skb->len == 0) { +			/* Pull skb off the list - it will be freed in the callback */ +			if (!skb_queue_empty(&nesqp->pau_list)) +				skb_unlink(frags[i].skb, &nesqp->pau_list); +		} else { +			/* Last skb still has data so update the seq */ +			iph = (struct iphdr *)(cb->data_start + ETH_HLEN); +			tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); +			tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt); +		} +	} + +out: +	if (rc) { +		if (fpdu_info) { +			if (fpdu_info->cqp_request) +				nes_put_cqp_request(nesdev, fpdu_info->cqp_request); +			kfree(fpdu_info); +		} +	} +	return rc; +} + +/** + * forward_fpdu - send complete fpdus, one at a time + */ +static int forward_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp) +{ +	struct nes_device *nesdev = nesvnic->nesdev; +	struct pau_fpdu_info *fpdu_info; +	struct nes_hw_cqp_wqe *cqp_wqe; +	struct nes_cqp_request *cqp_request; +	unsigned long flags; +	u64 u64tmp; +	u32 u32tmp; +	int rc; + +	while (1) { +		spin_lock_irqsave(&nesqp->pau_lock, flags); +		rc = get_fpdu_info(nesdev, nesqp, &fpdu_info); +		if (rc || (fpdu_info == NULL)) { +			spin_unlock_irqrestore(&nesqp->pau_lock, flags); +			return rc; +		} + +		cqp_request = fpdu_info->cqp_request; +		cqp_wqe = &cqp_request->cqp_wqe; +		nes_fill_init_cqp_wqe(cqp_wqe, nesdev); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_OPCODE_IDX, +				    NES_CQP_DOWNLOAD_SEGMENT | +				    (((u32)nesvnic->logical_port) << NES_CQP_OP_LOGICAL_PORT_SHIFT)); + +		u32tmp = fpdu_info->hdr_len << 16; +		u32tmp |= fpdu_info->hdr_len + (u32)fpdu_info->data_len; +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX, +				    u32tmp); + +		u32tmp = (fpdu_info->frags[1].frag_len << 16) | fpdu_info->frags[0].frag_len; +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_2_1_IDX, +				    u32tmp); + +		u32tmp = (fpdu_info->frags[3].frag_len << 16) | fpdu_info->frags[2].frag_len; +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_4_3_IDX, +				    u32tmp); + +		u64tmp = (u64)fpdu_info->hdr_pbase; +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX, +				    lower_32_bits(u64tmp)); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_HIGH_IDX, +				    upper_32_bits(u64tmp)); + +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX, +				    lower_32_bits(fpdu_info->frags[0].physaddr)); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_HIGH_IDX, +				    upper_32_bits(fpdu_info->frags[0].physaddr)); + +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_LOW_IDX, +				    lower_32_bits(fpdu_info->frags[1].physaddr)); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_HIGH_IDX, +				    upper_32_bits(fpdu_info->frags[1].physaddr)); + +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_LOW_IDX, +				    lower_32_bits(fpdu_info->frags[2].physaddr)); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_HIGH_IDX, +				    upper_32_bits(fpdu_info->frags[2].physaddr)); + +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_LOW_IDX, +				    lower_32_bits(fpdu_info->frags[3].physaddr)); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_HIGH_IDX, +				    upper_32_bits(fpdu_info->frags[3].physaddr)); + +		cqp_request->cqp_callback_pointer = fpdu_info; +		cqp_request->callback = 1; +		cqp_request->cqp_callback = nes_download_callback; + +		atomic_set(&cqp_request->refcount, 1); +		nes_post_cqp_request(nesdev, cqp_request); +		spin_unlock_irqrestore(&nesqp->pau_lock, flags); +	} + +	return 0; +} + +static void process_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp) +{ +	int again = 1; +	unsigned long flags; + +	do { +		/* Ignore rc - if it failed, tcp retries will cause it to try again */ +		forward_fpdus(nesvnic, nesqp); + +		spin_lock_irqsave(&nesqp->pau_lock, flags); +		if (nesqp->pau_pending) { +			nesqp->pau_pending = 0; +		} else { +			nesqp->pau_busy = 0; +			again = 0; +		} + +		spin_unlock_irqrestore(&nesqp->pau_lock, flags); +	} while (again); +} + +/** + * queue_fpdus - Handle fpdu's that hw passed up to sw + */ +static void queue_fpdus(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp) +{ +	struct sk_buff *tmpskb; +	struct nes_rskb_cb *cb; +	struct iphdr *iph; +	struct tcphdr *tcph; +	unsigned char *tcph_end; +	u32 rcv_nxt; +	u32 rcv_wnd; +	u32 seqnum; +	u32 len; +	bool process_it = false; +	unsigned long flags; + +	/* Move data ptr to after tcp header */ +	iph = (struct iphdr *)skb->data; +	tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); +	seqnum = be32_to_cpu(tcph->seq); +	tcph_end = (((char *)tcph) + (4 * tcph->doff)); + +	len = be16_to_cpu(iph->tot_len); +	if (skb->len > len) +		skb_trim(skb, len); +	skb_pull(skb, tcph_end - skb->data); + +	/* Initialize tracking values */ +	cb = (struct nes_rskb_cb *)&skb->cb[0]; +	cb->seqnum = seqnum; + +	/* Make sure data is in the receive window */ +	rcv_nxt = nesqp->pau_rcv_nxt; +	rcv_wnd = le32_to_cpu(nesqp->nesqp_context->rcv_wnd); +	if (!between(seqnum, rcv_nxt, (rcv_nxt + rcv_wnd))) { +		nes_mgt_free_skb(nesvnic->nesdev, skb, PCI_DMA_TODEVICE); +		nes_rem_ref_cm_node(nesqp->cm_node); +		return; +	} + +	spin_lock_irqsave(&nesqp->pau_lock, flags); + +	if (nesqp->pau_busy) +		nesqp->pau_pending = 1; +	else +		nesqp->pau_busy = 1; + +	/* Queue skb by sequence number */ +	if (skb_queue_len(&nesqp->pau_list) == 0) { +		skb_queue_head(&nesqp->pau_list, skb); +	} else { +		tmpskb = nesqp->pau_list.next; +		while (tmpskb != (struct sk_buff *)&nesqp->pau_list) { +			cb = (struct nes_rskb_cb *)&tmpskb->cb[0]; +			if (before(seqnum, cb->seqnum)) +				break; +			tmpskb = tmpskb->next; +		} +		skb_insert(tmpskb, skb, &nesqp->pau_list); +	} +	if (nesqp->pau_state == PAU_READY) +		process_it = true; +	spin_unlock_irqrestore(&nesqp->pau_lock, flags); + +	if (process_it) +		process_fpdus(nesvnic, nesqp); + +	return; +} + +/** + * mgt_thread - Handle mgt skbs in a safe context + */ +static int mgt_thread(void *context) +{ +	struct nes_vnic *nesvnic = context; +	struct sk_buff *skb; +	struct nes_rskb_cb *cb; + +	while (!kthread_should_stop()) { +		wait_event_interruptible(nesvnic->mgt_wait_queue, +					 skb_queue_len(&nesvnic->mgt_skb_list) || kthread_should_stop()); +		while ((skb_queue_len(&nesvnic->mgt_skb_list)) && !kthread_should_stop()) { +			skb = skb_dequeue(&nesvnic->mgt_skb_list); +			cb = (struct nes_rskb_cb *)&skb->cb[0]; +			cb->data_start = skb->data - ETH_HLEN; +			cb->busaddr = pci_map_single(nesvnic->nesdev->pcidev, cb->data_start, +						     nesvnic->max_frame_size, PCI_DMA_TODEVICE); +			queue_fpdus(skb, nesvnic, cb->nesqp); +		} +	} + +	/* Closing down so delete any entries on the queue */ +	while (skb_queue_len(&nesvnic->mgt_skb_list)) { +		skb = skb_dequeue(&nesvnic->mgt_skb_list); +		cb = (struct nes_rskb_cb *)&skb->cb[0]; +		nes_rem_ref_cm_node(cb->nesqp->cm_node); +		dev_kfree_skb_any(skb); +	} +	return 0; +} + +/** + * nes_queue_skbs - Queue skb so it can be handled in a thread context + */ +void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp) +{ +	struct nes_rskb_cb *cb; + +	cb = (struct nes_rskb_cb *)&skb->cb[0]; +	cb->nesqp = nesqp; +	skb_queue_tail(&nesvnic->mgt_skb_list, skb); +	wake_up_interruptible(&nesvnic->mgt_wait_queue); +} + +void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp) +{ +	struct sk_buff *skb; +	unsigned long flags; +	atomic_inc(&pau_qps_destroyed); + +	/* Free packets that have not yet been forwarded */ +	/* Lock is acquired by skb_dequeue when removing the skb */ +	spin_lock_irqsave(&nesqp->pau_lock, flags); +	while (skb_queue_len(&nesqp->pau_list)) { +		skb = skb_dequeue(&nesqp->pau_list); +		nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE); +		nes_rem_ref_cm_node(nesqp->cm_node); +	} +	spin_unlock_irqrestore(&nesqp->pau_lock, flags); +} + +static void nes_chg_qh_handler(struct nes_device *nesdev, struct nes_cqp_request *cqp_request) +{ +	struct pau_qh_chg *qh_chg = cqp_request->cqp_callback_pointer; +	struct nes_cqp_request *new_request; +	struct nes_hw_cqp_wqe *cqp_wqe; +	struct nes_adapter *nesadapter; +	struct nes_qp *nesqp; +	struct nes_v4_quad nes_quad; +	u32 crc_value; +	u64 u64temp; + +	nesadapter = nesdev->nesadapter; +	nesqp = qh_chg->nesqp; + +	/* Should we handle the bad completion */ +	if (cqp_request->major_code) +		WARN(1, PFX "Invalid cqp_request major_code=0x%x\n", +		       cqp_request->major_code); + +	switch (nesqp->pau_state) { +	case PAU_DEL_QH: +		/* Old hash code deleted, now set the new one */ +		nesqp->pau_state = PAU_ADD_LB_QH; +		new_request = nes_get_cqp_request(nesdev); +		if (new_request == NULL) { +			nes_debug(NES_DBG_PAU, "Failed to get a new_request.\n"); +			WARN_ON(1); +			return; +		} + +		memset(&nes_quad, 0, sizeof(nes_quad)); +		nes_quad.DstIpAdrIndex = +			cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); +		nes_quad.SrcIpadr = cpu_to_be32(0x7f000001); +		nes_quad.TcpPorts[0] = swab16(nesqp->nesqp_context->tcpPorts[1]); +		nes_quad.TcpPorts[1] = swab16(nesqp->nesqp_context->tcpPorts[0]); + +		/* Produce hash key */ +		crc_value = get_crc_value(&nes_quad); +		nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff); +		nes_debug(NES_DBG_PAU, "new HTE Index = 0x%08X, 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->nesqp_context->ip0 = cpu_to_le32(0x7f000001); +		nesqp->nesqp_context->rcv_nxt = cpu_to_le32(nesqp->pau_rcv_nxt); + +		cqp_wqe = &new_request->cqp_wqe; +		nes_fill_init_cqp_wqe(cqp_wqe, nesdev); +		set_wqe_32bit_value(cqp_wqe->wqe_words, +				    NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH | +				    NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS); +		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_debug(NES_DBG_PAU, "Waiting for CQP completion for adding the quad hash.\n"); + +		new_request->cqp_callback_pointer = qh_chg; +		new_request->callback = 1; +		new_request->cqp_callback = nes_chg_qh_handler; +		atomic_set(&new_request->refcount, 1); +		nes_post_cqp_request(nesdev, new_request); +		break; + +	case PAU_ADD_LB_QH: +		/* Start processing the queued fpdu's */ +		nesqp->pau_state = PAU_READY; +		process_fpdus(qh_chg->nesvnic, qh_chg->nesqp); +		kfree(qh_chg); +		break; +	} +} + +/** + * nes_change_quad_hash + */ +static int nes_change_quad_hash(struct nes_device *nesdev, +				struct nes_vnic *nesvnic, struct nes_qp *nesqp) +{ +	struct nes_cqp_request *cqp_request = NULL; +	struct pau_qh_chg *qh_chg = NULL; +	u64 u64temp; +	struct nes_hw_cqp_wqe *cqp_wqe; +	int ret = 0; + +	cqp_request = nes_get_cqp_request(nesdev); +	if (cqp_request == NULL) { +		nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); +		ret = -ENOMEM; +		goto chg_qh_err; +	} + +	qh_chg = kmalloc(sizeof *qh_chg, GFP_ATOMIC); +	if (qh_chg == NULL) { +		nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); +		ret = -ENOMEM; +		goto chg_qh_err; +	} +	qh_chg->nesdev = nesdev; +	qh_chg->nesvnic = nesvnic; +	qh_chg->nesqp = nesqp; +	nesqp->pau_state = PAU_DEL_QH; + +	cqp_wqe = &cqp_request->cqp_wqe; +	nes_fill_init_cqp_wqe(cqp_wqe, nesdev); +	set_wqe_32bit_value(cqp_wqe->wqe_words, +			    NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH | NES_CQP_QP_DEL_HTE | +			    NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS); +	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_debug(NES_DBG_PAU, "Waiting for CQP completion for deleting the quad hash.\n"); + +	cqp_request->cqp_callback_pointer = qh_chg; +	cqp_request->callback = 1; +	cqp_request->cqp_callback = nes_chg_qh_handler; +	atomic_set(&cqp_request->refcount, 1); +	nes_post_cqp_request(nesdev, cqp_request); + +	return ret; + +chg_qh_err: +	kfree(qh_chg); +	if (cqp_request) +		nes_put_cqp_request(nesdev, cqp_request); +	return ret; +} + +/** + * nes_mgt_ce_handler + * This management code deals with any packed and unaligned (pau) fpdu's + * that the hardware cannot handle. + */ +static void nes_mgt_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) +{ +	struct nes_vnic_mgt *mgtvnic = container_of(cq, struct nes_vnic_mgt, mgt_cq); +	struct nes_adapter *nesadapter = nesdev->nesadapter; +	u32 head; +	u32 cq_size; +	u32 cqe_count = 0; +	u32 cqe_misc; +	u32 qp_id = 0; +	u32 skbs_needed; +	unsigned long context; +	struct nes_qp *nesqp; +	struct sk_buff *rx_skb; +	struct nes_rskb_cb *cb; + +	head = cq->cq_head; +	cq_size = cq->cq_size; + +	while (1) { +		cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]); +		if (!(cqe_misc & NES_NIC_CQE_VALID)) +			break; + +		nesqp = NULL; +		if (cqe_misc & NES_NIC_CQE_ACCQP_VALID) { +			qp_id = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_ACCQP_ID_IDX]); +			qp_id &= 0x001fffff; +			if (qp_id < nesadapter->max_qp) { +				context = (unsigned long)nesadapter->qp_table[qp_id - NES_FIRST_QPN]; +				nesqp = (struct nes_qp *)context; +			} +		} + +		if (nesqp) { +			if (nesqp->pau_mode == false) { +				nesqp->pau_mode = true; /* First time for this qp */ +				nesqp->pau_rcv_nxt = le32_to_cpu( +					cq->cq_vbase[head].cqe_words[NES_NIC_CQE_HASH_RCVNXT]); +				skb_queue_head_init(&nesqp->pau_list); +				spin_lock_init(&nesqp->pau_lock); +				atomic_inc(&pau_qps_created); +				nes_change_quad_hash(nesdev, mgtvnic->nesvnic, nesqp); +			} + +			rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail]; +			rx_skb->len = 0; +			skb_put(rx_skb, cqe_misc & 0x0000ffff); +			rx_skb->protocol = eth_type_trans(rx_skb, mgtvnic->nesvnic->netdev); +			cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; +			pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, PCI_DMA_FROMDEVICE); +			cb->busaddr = 0; +			mgtvnic->mgt.rq_tail++; +			mgtvnic->mgt.rq_tail &= mgtvnic->mgt.rq_size - 1; + +			nes_add_ref_cm_node(nesqp->cm_node); +			nes_queue_mgt_skbs(rx_skb, mgtvnic->nesvnic, nesqp); +		} else { +			printk(KERN_ERR PFX "Invalid QP %d for packed/unaligned handling\n", qp_id); +		} + +		cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0; +		cqe_count++; +		if (++head >= cq_size) +			head = 0; + +		if (cqe_count == 255) { +			/* Replenish mgt CQ */ +			nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); +			nesdev->currcq_count += cqe_count; +			cqe_count = 0; +		} + +		skbs_needed = atomic_inc_return(&mgtvnic->rx_skbs_needed); +		if (skbs_needed > (mgtvnic->mgt.rq_size >> 1)) +			nes_replenish_mgt_rq(mgtvnic); +	} + +	cq->cq_head = head; +	nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | +		    cq->cq_number | (cqe_count << 16)); +	nes_read32(nesdev->regs + NES_CQE_ALLOC); +	nesdev->currcq_count += cqe_count; +} + +/** + * nes_init_mgt_qp + */ +int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic) +{ +	struct nes_vnic_mgt *mgtvnic; +	u32 counter; +	void *vmem; +	dma_addr_t pmem; +	struct nes_hw_cqp_wqe *cqp_wqe; +	u32 cqp_head; +	unsigned long flags; +	struct nes_hw_nic_qp_context *mgt_context; +	u64 u64temp; +	struct nes_hw_nic_rq_wqe *mgt_rqe; +	struct sk_buff *skb; +	u32 wqe_count; +	struct nes_rskb_cb *cb; +	u32 mgt_mem_size; +	void *mgt_vbase; +	dma_addr_t mgt_pbase; +	int i; +	int ret; + +	/* Allocate space the all mgt QPs once */ +	mgtvnic = kzalloc(NES_MGT_QP_COUNT * sizeof(struct nes_vnic_mgt), GFP_KERNEL); +	if (mgtvnic == NULL) { +		nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt structure\n"); +		return -ENOMEM; +	} + +	/* Allocate fragment, RQ, and CQ; Reuse CEQ based on the PCI function */ +	/* We are not sending from this NIC so sq is not allocated */ +	mgt_mem_size = 256 + +		       (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)) + +		       (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_cqe)) + +		       sizeof(struct nes_hw_nic_qp_context); +	mgt_mem_size = (mgt_mem_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); +	mgt_vbase = pci_alloc_consistent(nesdev->pcidev, NES_MGT_QP_COUNT * mgt_mem_size, &mgt_pbase); +	if (!mgt_vbase) { +		kfree(mgtvnic); +		nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt host descriptor rings\n"); +		return -ENOMEM; +	} + +	nesvnic->mgt_mem_size = NES_MGT_QP_COUNT * mgt_mem_size; +	nesvnic->mgt_vbase = mgt_vbase; +	nesvnic->mgt_pbase = mgt_pbase; + +	skb_queue_head_init(&nesvnic->mgt_skb_list); +	init_waitqueue_head(&nesvnic->mgt_wait_queue); +	nesvnic->mgt_thread = kthread_run(mgt_thread, nesvnic, "nes_mgt_thread"); + +	for (i = 0; i < NES_MGT_QP_COUNT; i++) { +		mgtvnic->nesvnic = nesvnic; +		mgtvnic->mgt.qp_id = nesdev->mac_index + NES_MGT_QP_OFFSET + i; +		memset(mgt_vbase, 0, mgt_mem_size); +		nes_debug(NES_DBG_INIT, "Allocated mgt QP structures at %p (phys = %016lX), size = %u.\n", +			  mgt_vbase, (unsigned long)mgt_pbase, mgt_mem_size); + +		vmem = (void *)(((unsigned long)mgt_vbase + (256 - 1)) & +				~(unsigned long)(256 - 1)); +		pmem = (dma_addr_t)(((unsigned long long)mgt_pbase + (256 - 1)) & +				    ~(unsigned long long)(256 - 1)); + +		spin_lock_init(&mgtvnic->mgt.rq_lock); + +		/* setup the RQ */ +		mgtvnic->mgt.rq_vbase = vmem; +		mgtvnic->mgt.rq_pbase = pmem; +		mgtvnic->mgt.rq_head = 0; +		mgtvnic->mgt.rq_tail = 0; +		mgtvnic->mgt.rq_size = NES_MGT_WQ_COUNT; + +		/* setup the CQ */ +		vmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)); +		pmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)); + +		mgtvnic->mgt_cq.cq_number = mgtvnic->mgt.qp_id; +		mgtvnic->mgt_cq.cq_vbase = vmem; +		mgtvnic->mgt_cq.cq_pbase = pmem; +		mgtvnic->mgt_cq.cq_head = 0; +		mgtvnic->mgt_cq.cq_size = NES_MGT_WQ_COUNT; + +		mgtvnic->mgt_cq.ce_handler = nes_mgt_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)mgtvnic->mgt_cq.cq_size << 16)); +		cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32( +			mgtvnic->mgt_cq.cq_number | ((u32)nesdev->ceq_index << 16)); +		u64temp = (u64)mgtvnic->mgt_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)&mgtvnic->mgt_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 */ +		mgt_context = (void *)(&mgtvnic->mgt_cq.cq_vbase[mgtvnic->mgt_cq.cq_size]); +		mgt_context->context_words[NES_NIC_CTX_MISC_IDX] = +			cpu_to_le32((u32)NES_MGT_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) +			mgt_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE); + +		u64temp = (u64)mgtvnic->mgt.rq_pbase; +		mgt_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); +		mgt_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); +		u64temp = (u64)mgtvnic->mgt.rq_pbase; +		mgt_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); +		mgt_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(mgtvnic->mgt.qp_id); +		u64temp = (u64)mgtvnic->mgt_cq.cq_pbase + +			  (mgtvnic->mgt_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 MGT QP%u to complete.\n", +			  mgtvnic->mgt.qp_id); + +		ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head), +					 NES_EVENT_TIMEOUT); +		nes_debug(NES_DBG_INIT, "Create MGT QP%u completed, wait_event_timeout ret = %u.\n", +			  mgtvnic->mgt.qp_id, ret); +		if (!ret) { +			nes_debug(NES_DBG_INIT, "MGT QP%u create timeout expired\n", mgtvnic->mgt.qp_id); +			if (i == 0) { +				pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase, +						    nesvnic->mgt_pbase); +				kfree(mgtvnic); +			} else { +				nes_destroy_mgt(nesvnic); +			} +			return -EIO; +		} + +		/* Populate the RQ */ +		for (counter = 0; counter < (NES_MGT_WQ_COUNT - 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); +				return -ENOMEM; +			} + +			skb->dev = netdev; + +			pmem = pci_map_single(nesdev->pcidev, skb->data, +					      nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); +			cb = (struct nes_rskb_cb *)&skb->cb[0]; +			cb->busaddr = pmem; +			cb->maplen = nesvnic->max_frame_size; + +			mgt_rqe = &mgtvnic->mgt.rq_vbase[counter]; +			mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32((u32)nesvnic->max_frame_size); +			mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; +			mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); +			mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32)); +			mgtvnic->mgt.rx_skb[counter] = skb; +		} + +		init_timer(&mgtvnic->rq_wqes_timer); +		mgtvnic->rq_wqes_timer.function = nes_mgt_rq_wqes_timeout; +		mgtvnic->rq_wqes_timer.data = (unsigned long)mgtvnic; + +		wqe_count = NES_MGT_WQ_COUNT - 1; +		mgtvnic->mgt.rq_head = wqe_count; +		barrier(); +		do { +			counter = min(wqe_count, ((u32)255)); +			wqe_count -= counter; +			nes_write32(nesdev->regs + NES_WQE_ALLOC, (counter << 24) | mgtvnic->mgt.qp_id); +		} while (wqe_count); + +		nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | +			    mgtvnic->mgt_cq.cq_number); +		nes_read32(nesdev->regs + NES_CQE_ALLOC); + +		mgt_vbase += mgt_mem_size; +		mgt_pbase += mgt_mem_size; +		nesvnic->mgtvnic[i] = mgtvnic++; +	} +	return 0; +} + + +void nes_destroy_mgt(struct nes_vnic *nesvnic) +{ +	struct nes_device *nesdev = nesvnic->nesdev; +	struct nes_vnic_mgt *mgtvnic; +	struct nes_vnic_mgt *first_mgtvnic; +	unsigned long flags; +	struct nes_hw_cqp_wqe *cqp_wqe; +	u32 cqp_head; +	struct sk_buff *rx_skb; +	int i; +	int ret; + +	kthread_stop(nesvnic->mgt_thread); + +	/* Free remaining NIC receive buffers */ +	first_mgtvnic = nesvnic->mgtvnic[0]; +	for (i = 0; i < NES_MGT_QP_COUNT; i++) { +		mgtvnic = nesvnic->mgtvnic[i]; +		if (mgtvnic == NULL) +			continue; + +		while (mgtvnic->mgt.rq_head != mgtvnic->mgt.rq_tail) { +			rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail]; +			nes_mgt_free_skb(nesdev, rx_skb, PCI_DMA_FROMDEVICE); +			mgtvnic->mgt.rq_tail++; +			mgtvnic->mgt.rq_tail &= (mgtvnic->mgt.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, +				    mgtvnic->mgt.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)mgtvnic->mgt_cq.cq_size << 16))); +		set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, +				    (mgtvnic->mgt_cq.cq_number | ((u32)nesdev->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 MGT 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, "MGT QP%u destroy timeout expired\n", +				  mgtvnic->mgt.qp_id); + +		nesvnic->mgtvnic[i] = NULL; +	} + +	if (nesvnic->mgt_vbase) { +		pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase, +				    nesvnic->mgt_pbase); +		nesvnic->mgt_vbase = NULL; +		nesvnic->mgt_pbase = 0; +	} + +	kfree(first_mgtvnic); +} diff --git a/drivers/infiniband/hw/nes/nes_mgt.h b/drivers/infiniband/hw/nes/nes_mgt.h new file mode 100644 index 00000000000..4f7f701c4a8 --- /dev/null +++ b/drivers/infiniband/hw/nes/nes_mgt.h @@ -0,0 +1,97 @@ +/* +* Copyright (c) 2006 - 2011 Intel-NE, Inc.  All rights reserved. +* +* This software is available to you under a choice of one of two +* licenses.  You may choose to be licensed under the terms of the GNU +* 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_MGT_H +#define __NES_MGT_H + +#define MPA_FRAMING 6	/* length is 2 bytes, crc is 4 bytes */ + +int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic); +void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp); +void nes_destroy_mgt(struct nes_vnic *nesvnic); +void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp); + +struct nes_hw_mgt { +	struct nes_hw_nic_rq_wqe *rq_vbase;	/* virtual address of rq */ +	dma_addr_t rq_pbase;			/* PCI memory for host rings */ +	struct sk_buff *rx_skb[NES_NIC_WQ_SIZE]; +	u16 qp_id; +	u16 sq_head; +	u16 rq_head; +	u16 rq_tail; +	u16 rq_size; +	u8 replenishing_rq; +	u8 reserved; +	spinlock_t rq_lock; +}; + +struct nes_vnic_mgt { +	struct nes_vnic        *nesvnic; +	struct nes_hw_mgt      mgt; +	struct nes_hw_nic_cq   mgt_cq; +	atomic_t               rx_skbs_needed; +	struct timer_list      rq_wqes_timer; +	atomic_t               rx_skb_timer_running; +}; + +#define MAX_FPDU_FRAGS 4 +struct pau_fpdu_frag { +	struct sk_buff         *skb; +	u64                    physaddr; +	u32                    frag_len; +	bool                   cmplt; +}; + +struct pau_fpdu_info { +	struct nes_qp          *nesqp; +	struct nes_cqp_request *cqp_request; +	void                   *hdr_vbase; +	dma_addr_t             hdr_pbase; +	int                    hdr_len; +	u16                    data_len; +	u16                    frag_cnt; +	struct pau_fpdu_frag   frags[MAX_FPDU_FRAGS]; +}; + +enum pau_qh_state { +	PAU_DEL_QH, +	PAU_ADD_LB_QH, +	PAU_READY +}; + +struct pau_qh_chg { +	struct nes_device *nesdev; +	struct nes_vnic *nesvnic; +	struct nes_qp *nesqp; +}; + +#endif          /* __NES_MGT_H */ diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 3892e2c0e95..49eb5111d2c 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -144,6 +144,7 @@ static int nes_netdev_open(struct net_device *netdev)  	u32 nic_active_bit;  	u32 nic_active;  	struct list_head *list_pos, *list_temp; +	unsigned long flags;  	assert(nesdev != NULL); @@ -233,18 +234,35 @@ static int nes_netdev_open(struct net_device *netdev)  		first_nesvnic = nesvnic;  	} -	if (nesvnic->of_device_registered) { -		nesdev->iw_status = 1; -		nesdev->nesadapter->send_term_ok = 1; -		nes_port_ibevent(nesvnic); -	} -  	if (first_nesvnic->linkup) {  		/* Enable network packets */  		nesvnic->linkup = 1;  		netif_start_queue(netdev);  		netif_carrier_on(netdev);  	} + +	spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); +	if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) { +		nesdev->link_recheck = 1; +		mod_delayed_work(system_wq, &nesdev->work, +				 NES_LINK_RECHECK_DELAY); +	} +	spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + +	spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); +	if (nesvnic->of_device_registered) { +		nesdev->nesadapter->send_term_ok = 1; +		if (nesvnic->linkup == 1) { +			if (nesdev->iw_status == 0) { +				nesdev->iw_status = 1; +				nes_port_ibevent(nesvnic); +			} +		} else { +			nesdev->iw_status = 0; +		} +	} +	spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); +  	napi_enable(&nesvnic->napi);  	nesvnic->netdev_open = 1; @@ -263,6 +281,7 @@ static int nes_netdev_stop(struct net_device *netdev)  	u32 nic_active;  	struct nes_vnic *first_nesvnic = NULL;  	struct list_head *list_pos, *list_temp; +	unsigned long flags;  	nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",  			nesvnic, nesdev, netdev, netdev->name); @@ -315,12 +334,17 @@ static int nes_netdev_stop(struct net_device *netdev)  	nic_active &= nic_active_mask;  	nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - +	spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);  	if (nesvnic->of_device_registered) {  		nesdev->nesadapter->send_term_ok = 0;  		nesdev->iw_status = 0; -		nes_port_ibevent(nesvnic); +		if (nesvnic->linkup == 1) +			nes_port_ibevent(nesvnic);  	} +	del_timer_sync(&nesvnic->event_timer); +	nesvnic->event_timer.function = NULL; +	spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); +  	nes_destroy_nic_qp(nesvnic);  	nesvnic->netdev_open = 0; @@ -360,24 +384,20 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)  	/* bump past the vlan tag */  	wqe_fragment_length++;  	/*	wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX]; */ +	wqe_misc |= NES_NIC_SQ_WQE_COMPLETION;  	if (skb->ip_summed == CHECKSUM_PARTIAL) { -		tcph = tcp_hdr(skb); -		if (1) { -			if (skb_is_gso(skb)) { -				/* nes_debug(NES_DBG_NIC_TX, "%s: TSO request... seg size = %u\n", -						netdev->name, skb_is_gso(skb)); */ -				wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE | -						NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb); -				set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX, -						((u32)tcph->doff) | -						(((u32)(((unsigned char *)tcph) - skb->data)) << 4)); -			} else { -				wqe_misc |= NES_NIC_SQ_WQE_COMPLETION; -			} +		if (skb_is_gso(skb)) { +			tcph = tcp_hdr(skb); +			/* nes_debug(NES_DBG_NIC_TX, "%s: TSO request... is_gso = %u seg size = %u\n", +					netdev->name, skb_is_gso(skb), skb_shinfo(skb)->gso_size); */ +			wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE | (u16)skb_shinfo(skb)->gso_size; +			set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX, +					((u32)tcph->doff) | +					(((u32)(((unsigned char *)tcph) - skb->data)) << 4));  		}  	} else {	/* CHECKSUM_HW */ -		wqe_misc |= NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION; +		wqe_misc |= NES_NIC_SQ_WQE_DISABLE_CHKSUM;  	}  	set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX, @@ -416,13 +436,13 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)  		nesnic->tx_skb[nesnic->sq_head] = skb;  		for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;  				skb_fragment_index++) { -			bus_address = pci_map_page( nesdev->pcidev, -					skb_shinfo(skb)->frags[skb_fragment_index].page, -					skb_shinfo(skb)->frags[skb_fragment_index].page_offset, -					skb_shinfo(skb)->frags[skb_fragment_index].size, -					PCI_DMA_TODEVICE); +			skb_frag_t *frag = +				&skb_shinfo(skb)->frags[skb_fragment_index]; +			bus_address = skb_frag_dma_map(&nesdev->pcidev->dev, +						       frag, 0, skb_frag_size(frag), +						       DMA_TO_DEVICE);  			wqe_fragment_length[wqe_fragment_index] = -					cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size); +					cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[skb_fragment_index]));  			set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),  				bus_address);  			wqe_fragment_index++; @@ -536,11 +556,12 @@ tso_sq_no_longer_full:  			/* Map all the buffers */  			for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;  					tso_frag_count++) { -				tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev, -						skb_shinfo(skb)->frags[tso_frag_count].page, -						skb_shinfo(skb)->frags[tso_frag_count].page_offset, -						skb_shinfo(skb)->frags[tso_frag_count].size, -						PCI_DMA_TODEVICE); +				skb_frag_t *frag = +					&skb_shinfo(skb)->frags[tso_frag_count]; +				tso_bus_address[tso_frag_count] = +					skb_frag_dma_map(&nesdev->pcidev->dev, +							 frag, 0, skb_frag_size(frag), +							 DMA_TO_DEVICE);  			}  			tso_frag_index = 0; @@ -571,10 +592,10 @@ tso_sq_no_longer_full:  					nes_debug(NES_DBG_NIC_TX, "ERROR: SKB header too big, headlen=%u, FIRST_FRAG_SIZE=%u\n",  							original_first_length, NES_FIRST_FRAG_SIZE);  					nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," -							" (%u frags), tso_size=%u\n", +							" (%u frags), is_gso = %u tso_size=%u\n",  							netdev->name,  							skb->len, skb_headlen(skb), -							skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); +							skb_shinfo(skb)->nr_frags, skb_is_gso(skb), skb_shinfo(skb)->gso_size);  				}  				memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,  						skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), @@ -611,11 +632,11 @@ tso_sq_no_longer_full:  				}  				while (wqe_fragment_index < 5) {  					wqe_fragment_length[wqe_fragment_index] = -							cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size); +							cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index]));  					set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),  						(u64)tso_bus_address[tso_frag_index]);  					wqe_fragment_index++; -					tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size; +					tso_wqe_length += skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index++]);  					if (wqe_fragment_index < 5)  						wqe_fragment_length[wqe_fragment_index] = 0;  					if (tso_frag_index == tso_frag_count) @@ -626,8 +647,8 @@ tso_sq_no_longer_full:  				} else {  					nesnic->tx_skb[nesnic->sq_head] = NULL;  				} -				wqe_misc |= NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb); -				if ((tso_wqe_length + original_first_length) > skb_is_gso(skb)) { +				wqe_misc |= NES_NIC_SQ_WQE_COMPLETION | (u16)skb_shinfo(skb)->gso_size; +				if ((tso_wqe_length + original_first_length) > skb_shinfo(skb)->gso_size) {  					wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE;  				} else {  					iph->tot_len = htons(tso_wqe_length + original_first_length - nhoffset); @@ -877,7 +898,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)  		nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);  	} -	nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n", +	nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscuous = %d, All Multicast = %d.\n",  		  mc_count, !!(netdev->flags & IFF_PROMISC),  		  !!(netdev->flags & IFF_ALLMULTI));  	if (!mc_all_on) { @@ -908,8 +929,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)  					nesvnic->nic_index &&  					mc_index < max_pft_entries_avaiable) {  						nes_debug(NES_DBG_NIC_RX, -					"mc_index=%d skipping nic_index=%d,\ -					used for=%d \n", mc_index, +					"mc_index=%d skipping nic_index=%d, " +					"used for=%d \n", mc_index,  					nesvnic->nic_index,  					nesadapter->pft_mcast_map[mc_index]);  				mc_index++; @@ -923,12 +944,13 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)  					  addr,  					  perfect_filter_register_address+(mc_index * 8),  					  mc_nic_index); -				macaddr_high  = ((u16) addr[0]) << 8; -				macaddr_high += (u16) addr[1]; -				macaddr_low   = ((u32) addr[2]) << 24; -				macaddr_low  += ((u32) addr[3]) << 16; -				macaddr_low  += ((u32) addr[4]) << 8; -				macaddr_low  += (u32) addr[5]; +				macaddr_high  = ((u8) addr[0]) << 8; +				macaddr_high += (u8) addr[1]; +				macaddr_low   = ((u8) addr[2]) << 24; +				macaddr_low  += ((u8) addr[3]) << 16; +				macaddr_low  += ((u8) addr[4]) << 8; +				macaddr_low  += (u8) addr[5]; +  				nes_write_indexed(nesdev,  						perfect_filter_register_address+(mc_index * 8),  						macaddr_low); @@ -1065,37 +1087,11 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {  	"LRO aggregated",  	"LRO flushed",  	"LRO no_desc", +	"PAU CreateQPs", +	"PAU DestroyQPs",  };  #define NES_ETHTOOL_STAT_COUNT  ARRAY_SIZE(nes_ethtool_stringset) -/** - * nes_netdev_get_rx_csum - */ -static u32 nes_netdev_get_rx_csum (struct net_device *netdev) -{ -	struct nes_vnic *nesvnic = netdev_priv(netdev); - -	if (nesvnic->rx_checksum_disabled) -		return 0; -	else -		return 1; -} - - -/** - * nes_netdev_set_rc_csum - */ -static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable) -{ -	struct nes_vnic *nesvnic = netdev_priv(netdev); - -	if (enable) -		nesvnic->rx_checksum_disabled = 0; -	else -		nesvnic->rx_checksum_disabled = 1; -	return 0; -} -  /**   * nes_netdev_get_sset_count @@ -1308,6 +1304,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,  	target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated;  	target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed;  	target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc; +	target_stat_values[++index] = atomic_read(&pau_qps_created); +	target_stat_values[++index] = atomic_read(&pau_qps_destroyed);  }  /** @@ -1319,11 +1317,13 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,  	struct nes_vnic *nesvnic = netdev_priv(netdev);  	struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter; -	strcpy(drvinfo->driver, DRV_NAME); -	strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev)); -	sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16, -				nesadapter->firmware_version & 0x000000ff); -	strcpy(drvinfo->version, DRV_VERSION); +	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); +	strlcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev), +		sizeof(drvinfo->bus_info)); +	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), +		 "%u.%u", nesadapter->firmware_version >> 16, +		 nesadapter->firmware_version & 0x000000ff); +	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));  	drvinfo->testinfo_len = 0;  	drvinfo->eedump_len = 0;  	drvinfo->regdump_len = 0; @@ -1496,7 +1496,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd  	et_cmd->maxrxpkt = 511;  	if (nesadapter->OneG_Mode) { -		et_cmd->speed = SPEED_1000; +		ethtool_cmd_speed_set(et_cmd, SPEED_1000);  		if (phy_type == NES_PHY_TYPE_PUMA_1G) {  			et_cmd->supported   = SUPPORTED_1000baseT_Full;  			et_cmd->advertising = ADVERTISED_1000baseT_Full; @@ -1535,7 +1535,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd  		et_cmd->advertising = ADVERTISED_10000baseT_Full;  		et_cmd->phy_address = mac_index;  	} -	et_cmd->speed = SPEED_10000; +	ethtool_cmd_speed_set(et_cmd, SPEED_10000);  	et_cmd->autoneg = AUTONEG_DISABLE;  	return 0;  } @@ -1573,19 +1573,10 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd  } -static int nes_netdev_set_flags(struct net_device *netdev, u32 flags) -{ -	return ethtool_op_set_flags(netdev, flags, ETH_FLAG_LRO); -} - -  static const struct ethtool_ops nes_ethtool_ops = {  	.get_link = ethtool_op_get_link,  	.get_settings = nes_netdev_get_settings,  	.set_settings = nes_netdev_set_settings, -	.get_tx_csum = ethtool_op_get_tx_csum, -	.get_rx_csum = nes_netdev_get_rx_csum, -	.get_sg = ethtool_op_get_sg,  	.get_strings = nes_netdev_get_strings,  	.get_sset_count = nes_netdev_get_sset_count,  	.get_ethtool_stats = nes_netdev_get_ethtool_stats, @@ -1594,32 +1585,21 @@ static const struct ethtool_ops nes_ethtool_ops = {  	.set_coalesce = nes_netdev_set_coalesce,  	.get_pauseparam = nes_netdev_get_pauseparam,  	.set_pauseparam = nes_netdev_set_pauseparam, -	.set_tx_csum = ethtool_op_set_tx_csum, -	.set_rx_csum = nes_netdev_set_rx_csum, -	.set_sg = ethtool_op_set_sg, -	.get_tso = ethtool_op_get_tso, -	.set_tso = ethtool_op_set_tso, -	.get_flags = ethtool_op_get_flags, -	.set_flags = nes_netdev_set_flags,  }; - -static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) +static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, netdev_features_t features)  { -	struct nes_vnic *nesvnic = netdev_priv(netdev); -	struct nes_device *nesdev = nesvnic->nesdev;  	struct nes_adapter *nesadapter = nesdev->nesadapter;  	u32 u32temp;  	unsigned long flags;  	spin_lock_irqsave(&nesadapter->phy_lock, flags); -	nesvnic->vlan_grp = grp;  	nes_debug(NES_DBG_NETDEV, "%s: %s\n", __func__, netdev->name);  	/* Enable/Disable VLAN Stripping */  	u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG); -	if (grp) +	if (features & NETIF_F_HW_VLAN_CTAG_RX)  		u32temp &= 0xfdffffff;  	else  		u32temp	|= 0x02000000; @@ -1628,17 +1608,44 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g  	spin_unlock_irqrestore(&nesadapter->phy_lock, flags);  } +static netdev_features_t nes_fix_features(struct net_device *netdev, netdev_features_t features) +{ +	/* +	 * Since there is no support for separate rx/tx vlan accel +	 * enable/disable make sure tx flag is always in same state as rx. +	 */ +	if (features & NETIF_F_HW_VLAN_CTAG_RX) +		features |= NETIF_F_HW_VLAN_CTAG_TX; +	else +		features &= ~NETIF_F_HW_VLAN_CTAG_TX; + +	return features; +} + +static int nes_set_features(struct net_device *netdev, netdev_features_t features) +{ +	struct nes_vnic *nesvnic = netdev_priv(netdev); +	struct nes_device *nesdev = nesvnic->nesdev; +	u32 changed = netdev->features ^ features; + +	if (changed & NETIF_F_HW_VLAN_CTAG_RX) +		nes_vlan_mode(netdev, nesdev, features); + +	return 0; +} +  static const struct net_device_ops nes_netdev_ops = { -	.ndo_open 		= nes_netdev_open, +	.ndo_open		= nes_netdev_open,  	.ndo_stop		= nes_netdev_stop, -	.ndo_start_xmit 	= nes_netdev_start_xmit, +	.ndo_start_xmit		= nes_netdev_start_xmit,  	.ndo_get_stats		= nes_netdev_get_stats, -	.ndo_tx_timeout 	= nes_netdev_tx_timeout, +	.ndo_tx_timeout		= nes_netdev_tx_timeout,  	.ndo_set_mac_address	= nes_netdev_set_mac_address, -	.ndo_set_multicast_list = nes_netdev_set_multicast_list, +	.ndo_set_rx_mode	= nes_netdev_set_multicast_list,  	.ndo_change_mtu		= nes_netdev_change_mtu,  	.ndo_validate_addr	= eth_validate_addr, -	.ndo_vlan_rx_register 	= nes_netdev_vlan_rx_register, +	.ndo_fix_features	= nes_fix_features, +	.ndo_set_features	= nes_set_features,  };  /** @@ -1670,12 +1677,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  	netdev->hard_header_len = ETH_HLEN;  	netdev->addr_len = ETH_ALEN;  	netdev->type = ARPHRD_ETHER; -	netdev->features = NETIF_F_HIGHDMA;  	netdev->netdev_ops = &nes_netdev_ops;  	netdev->ethtool_ops = &nes_ethtool_ops;  	netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);  	nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n"); -	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;  	/* Fill in the port structure */  	nesvnic->netdev = netdev; @@ -1700,14 +1705,13 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  	netdev->dev_addr[3] = (u8)(u64temp>>16);  	netdev->dev_addr[4] = (u8)(u64temp>>8);  	netdev->dev_addr[5] = (u8)u64temp; -	memcpy(netdev->perm_addr, netdev->dev_addr, 6); -	if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) { -		netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; -		netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; -	} else { -		netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; -	} +	netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX; +	if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) +		netdev->hw_features |= NETIF_F_TSO; + +	netdev->features = netdev->hw_features | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX; +	netdev->hw_features |= NETIF_F_LRO;  	nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"  			" nic_index = %d, logical_port = %d, mac_index = %d.\n", @@ -1750,7 +1754,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  		nesvnic->rdma_enabled = 0;  	}  	nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id; +	init_timer(&nesvnic->event_timer); +	nesvnic->event_timer.function = NULL;  	spin_lock_init(&nesvnic->tx_lock); +	spin_lock_init(&nesvnic->port_ibevent_lock);  	nesdev->netdev[nesdev->netdev_count] = netdev;  	nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n", @@ -1763,8 +1770,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  	      (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||  	       ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {  		u32 u32temp; -		u32 link_mask; -		u32 link_val; +		u32 link_mask = 0; +		u32 link_val = 0; +		u16 temp_phy_data; +		u16 phy_data = 0; +		unsigned long flags;  		u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +  				(0x200 * (nesdev->mac_index & 1))); @@ -1786,6 +1796,23 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  				link_val = 0x02020000;  			}  			break; +		case NES_PHY_TYPE_SFP_D: +			spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); +			nes_read_10G_phy_reg(nesdev, +					     nesdev->nesadapter->phy_index[nesdev->mac_index], +					     1, 0x9003); +			temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); +			nes_read_10G_phy_reg(nesdev, +					     nesdev->nesadapter->phy_index[nesdev->mac_index], +					     3, 0x0021); +			nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); +			nes_read_10G_phy_reg(nesdev, +					     nesdev->nesadapter->phy_index[nesdev->mac_index], +					     3, 0x0021); +			phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); +			spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); +			phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; +			break;  		default:  			link_mask = 0x0f1f0000;  			link_val = 0x0f0f0000; @@ -1795,8 +1822,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  		u32temp = nes_read_indexed(nesdev,  					   NES_IDX_PHY_PCS_CONTROL_STATUS0 +  					   (0x200 * (nesdev->mac_index & 1))); -		if ((u32temp & link_mask) == link_val) -			nesvnic->linkup = 1; + +		if (phy_type == NES_PHY_TYPE_SFP_D) { +			if (phy_data & 0x0004) +				nesvnic->linkup = 1; +		} else { +			if ((u32temp & link_mask) == link_val) +				nesvnic->linkup = 1; +		}  		/* clear the MAC interrupt status, assumes direct logical to physical mapping */  		u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); @@ -1806,6 +1839,8 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,  		nes_init_phy(nesdev);  	} +	nes_vlan_mode(netdev, nesdev, netdev->features); +  	return netdev;  } diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h index 71e133ab209..529c421bb15 100644 --- a/drivers/infiniband/hw/nes/nes_user.h +++ b/drivers/infiniband/hw/nes/nes_user.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  All rights reserved.   * Copyright (c) 2005 Topspin Communications.  All rights reserved.   * Copyright (c) 2005 Cisco Systems.  All rights reserved.   * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. @@ -39,8 +39,8 @@  #include <linux/types.h> -#define NES_ABI_USERSPACE_VER 1 -#define NES_ABI_KERNEL_VER    1 +#define NES_ABI_USERSPACE_VER 2 +#define NES_ABI_KERNEL_VER    2  /*   * Make sure that all structs defined in this file remain laid out so @@ -78,6 +78,7 @@ struct nes_create_cq_req {  struct nes_create_qp_req {  	__u64 user_wqe_buffers; +	__u64 user_qp_buffer;  };  enum iwnes_memreg_type { diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index f9c417c6b3b..2042c0f2975 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -51,13 +51,34 @@  #include "nes.h" - -  static u16 nes_read16_eeprom(void __iomem *addr, u16 offset);  u32 mh_detected;  u32 mh_pauses_sent; +static u32 nes_set_pau(struct nes_device *nesdev) +{ +	u32 ret = 0; +	u32 counter; + +	nes_write_indexed(nesdev, NES_IDX_GPR2, NES_ENABLE_PAU); +	nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1); + +	for (counter = 0; counter < NES_PAU_COUNTER; counter++) { +		udelay(30); +		if (!nes_read_indexed(nesdev, NES_IDX_GPR2)) { +			printk(KERN_INFO PFX "PAU is supported.\n"); +			break; +		} +		nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1); +	} +	if (counter == NES_PAU_COUNTER) { +		printk(KERN_INFO PFX "PAU is not supported.\n"); +		return -EPERM; +	} +	return ret; +} +  /**   * nes_read_eeprom_values -   */ @@ -187,6 +208,11 @@ int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesada  		if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3))  			nesadapter->send_term_ok = 1; +		if (nes_drv_opt & NES_DRV_OPT_ENABLE_PAU) { +			if (!nes_set_pau(nesdev)) +				nesadapter->allow_unaligned_fpdus = 1; +		} +  		nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8))  <<  16) +  				(u32)((u8)eeprom_data); @@ -594,6 +620,7 @@ void nes_put_cqp_request(struct nes_device *nesdev,  		nes_free_cqp_request(nesdev, cqp_request);  } +  /**   * nes_post_cqp_request   */ @@ -604,6 +631,8 @@ void nes_post_cqp_request(struct nes_device *nesdev,  	unsigned long flags;  	u32 cqp_head;  	u64 u64temp; +	u32 opcode; +	int ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX;  	spin_lock_irqsave(&nesdev->cqp.lock, flags); @@ -614,17 +643,20 @@ void nes_post_cqp_request(struct nes_device *nesdev,  		nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;  		cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];  		memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe)); +		opcode = le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]); +		if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT) +			ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX;  		barrier();  		u64temp = (unsigned long)cqp_request; -		set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_SCRATCH_LOW_IDX, -				    u64temp); +		set_wqe_64bit_value(cqp_wqe->wqe_words, ctx_index, u64temp);  		nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ," -				" request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u," -				" waiting = %d, refcount = %d.\n", -				le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, -				le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request, -				nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size, -				cqp_request->waiting, atomic_read(&cqp_request->refcount)); +			" request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u," +			" waiting = %d, refcount = %d.\n", +			opcode & NES_CQP_OPCODE_MASK, +			le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request, +			nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size, +			cqp_request->waiting, atomic_read(&cqp_request->refcount)); +  		barrier();  		/* Ring doorbell (1 WQEs) */ @@ -645,7 +677,6 @@ void nes_post_cqp_request(struct nes_device *nesdev,  	return;  } -  /**   * nes_arp_table   */ @@ -668,7 +699,7 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti  		arp_index = 0;  		err = nes_alloc_resource(nesadapter, nesadapter->allocated_arps, -				nesadapter->arp_table_size, (u32 *)&arp_index, &nesadapter->next_arp_index); +				nesadapter->arp_table_size, (u32 *)&arp_index, &nesadapter->next_arp_index, NES_RESOURCE_ARP);  		if (err) {  			nes_debug(NES_DBG_NETDEV, "nes_alloc_resource returned error = %u\n", err);  			return err; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 99933e4e48f..218dd357428 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -55,7 +55,8 @@ static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev);  /**   * nes_alloc_mw   */ -static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) { +static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd, enum ib_mw_type type) +{  	struct nes_pd *nespd = to_nespd(ibpd);  	struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);  	struct nes_device *nesdev = nesvnic->nesdev; @@ -71,6 +72,9 @@ static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) {  	u32 driver_key = 0;  	u8 stag_key = 0; +	if (type != IB_MW_TYPE_1) +		return ERR_PTR(-EINVAL); +  	get_random_bytes(&next_stag_index, sizeof(next_stag_index));  	stag_key = (u8)next_stag_index; @@ -80,7 +84,7 @@ static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) {  	next_stag_index %= nesadapter->max_mr;  	ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, -			nesadapter->max_mr, &stag_index, &next_stag_index); +			nesadapter->max_mr, &stag_index, &next_stag_index, NES_RESOURCE_MW);  	if (ret) {  		return ERR_PTR(ret);  	} @@ -244,20 +248,19 @@ static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,  	if (ibmw_bind->send_flags & IB_SEND_SIGNALED)  		wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL; -	if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_WRITE) { +	if (ibmw_bind->bind_info.mw_access_flags & IB_ACCESS_REMOTE_WRITE)  		wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE; -	} -	if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_READ) { +	if (ibmw_bind->bind_info.mw_access_flags & IB_ACCESS_REMOTE_READ)  		wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_READ; -	}  	set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_MISC_IDX, wqe_misc); -	set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MR_IDX, ibmw_bind->mr->lkey); +	set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MR_IDX, +			    ibmw_bind->bind_info.mr->lkey);  	set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MW_IDX, ibmw->rkey);  	set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX, -			ibmw_bind->length); +			ibmw_bind->bind_info.length);  	wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX] = 0; -	u64temp = (u64)ibmw_bind->addr; +	u64temp = (u64)ibmw_bind->bind_info.addr;  	set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX, u64temp);  	head++; @@ -404,7 +407,7 @@ static struct ib_mr *nes_alloc_fast_reg_mr(struct ib_pd *ibpd, int max_page_list  	err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,  				 nesadapter->max_mr, &stag_index, -				 &next_stag_index); +				 &next_stag_index, NES_RESOURCE_FAST_MR);  	if (err)  		return ERR_PTR(err); @@ -597,7 +600,7 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr  	props->pkey_tbl_len = 1;  	props->qkey_viol_cntr = 0;  	props->active_width = IB_WIDTH_4X; -	props->active_speed = 1; +	props->active_speed = IB_SPEED_SDR;  	props->max_msg_sz = 0x80000000;  	return 0; @@ -605,16 +608,6 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr  /** - * nes_modify_port - */ -static int nes_modify_port(struct ib_device *ibdev, u8 port, -		int port_modify_mask, struct ib_port_modify *props) -{ -	return 0; -} - - -/**   * nes_query_pkey   */  static int nes_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) @@ -790,7 +783,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,  			netdev_refcnt_read(nesvnic->netdev));  	err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds, -			nesadapter->max_pd, &pd_num, &nesadapter->next_pd); +			nesadapter->max_pd, &pd_num, &nesadapter->next_pd, NES_RESOURCE_PD);  	if (err) {  		return ERR_PTR(err);  	} @@ -1167,7 +1160,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,  			nes_debug(NES_DBG_QP, "RQ size=%u, SQ Size=%u\n", rq_size, sq_size);  			ret = nes_alloc_resource(nesadapter, nesadapter->allocated_qps, -					nesadapter->max_qp, &qp_num, &nesadapter->next_qp); +					nesadapter->max_qp, &qp_num, &nesadapter->next_qp, NES_RESOURCE_QP);  			if (ret) {  				return ERR_PTR(ret);  			} @@ -1193,11 +1186,13 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,  					nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);  					kfree(nesqp->allocated_buffer);  					nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n"); -					return NULL; +					return ERR_PTR(-EFAULT);  				}  				if (req.user_wqe_buffers) {  					virt_wqs = 1;  				} +				if (req.user_qp_buffer) +					nesqp->nesuqp_addr = req.user_qp_buffer;  				if ((ibpd->uobject) && (ibpd->uobject->context)) {  					nesqp->user_mode = 1;  					nes_ucontext = to_nesucontext(ibpd->uobject->context); @@ -1391,6 +1386,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,  			if (ibpd->uobject) {  				uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index; +				uresp.mmap_rq_db_index = 0;  				uresp.actual_sq_size = sq_size;  				uresp.actual_rq_size = rq_size;  				uresp.qp_id = nesqp->hwqp.qp_id; @@ -1414,6 +1410,9 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,  	}  	nesqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR); +	init_timer(&nesqp->terminate_timer); +	nesqp->terminate_timer.function = nes_terminate_timeout; +	nesqp->terminate_timer.data = (unsigned long)nesqp;  	/* update the QP table */  	nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp; @@ -1423,7 +1422,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,  	return &nesqp->ibqp;  } -  /**   * nes_clean_cq   */ @@ -1468,7 +1466,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp)  	struct ib_qp_attr attr;  	struct iw_cm_id *cm_id;  	struct iw_cm_event cm_event; -	int ret; +	int ret = 0;  	atomic_inc(&sw_qps_destroyed);  	nesqp->destroyed = 1; @@ -1484,7 +1482,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp)  			(nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {  		cm_id = nesqp->cm_id;  		cm_event.event = IW_CM_EVENT_CONNECT_REPLY; -		cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT; +		cm_event.status = -ETIMEDOUT;  		cm_event.local_addr = cm_id->local_addr;  		cm_event.remote_addr = cm_id->remote_addr;  		cm_event.private_data = NULL; @@ -1521,7 +1519,6 @@ static int nes_destroy_qp(struct ib_qp *ibqp)  		if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq))  			nes_clean_cq(nesqp, nesqp->nesrcq);  	} -  	nes_rem_ref(&nesqp->ibqp);  	return 0;  } @@ -1557,7 +1554,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,  		return ERR_PTR(-EINVAL);  	err = nes_alloc_resource(nesadapter, nesadapter->allocated_cqs, -			nesadapter->max_cq, &cq_num, &nesadapter->next_cq); +			nesadapter->max_cq, &cq_num, &nesadapter->next_cq, NES_RESOURCE_CQ);  	if (err) {  		return ERR_PTR(err);  	} @@ -1773,7 +1770,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,  		resp.cq_id = nescq->hw_cq.cq_number;  		resp.cq_size = nescq->hw_cq.cq_size;  		resp.mmap_db_index = 0; -		if (ib_copy_to_udata(udata, &resp, sizeof resp)) { +		if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {  			nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);  			kfree(nescq);  			return ERR_PTR(-EFAULT); @@ -2140,7 +2137,7 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,  		return ERR_PTR(-EINVAL);  	err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr, -			&stag_index, &next_stag_index); +			&stag_index, &next_stag_index, NES_RESOURCE_PHYS_MR);  	if (err) {  		return ERR_PTR(err);  	} @@ -2312,7 +2309,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  	struct nes_device *nesdev = nesvnic->nesdev;  	struct nes_adapter *nesadapter = nesdev->nesadapter;  	struct ib_mr *ibmr = ERR_PTR(-EINVAL); -	struct ib_umem_chunk *chunk; +	struct scatterlist *sg;  	struct nes_ucontext *nes_ucontext;  	struct nes_pbl *nespbl;  	struct nes_mr *nesmr; @@ -2320,7 +2317,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  	struct nes_mem_reg_req req;  	struct nes_vpbl vpbl;  	struct nes_root_vpbl root_vpbl; -	int nmap_index, page_index; +	int entry, page_index;  	int page_count = 0;  	int err, pbl_depth = 0;  	int chunk_pages; @@ -2335,6 +2332,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  	u16 pbl_count;  	u8 single_page = 1;  	u8 stag_key; +	int first_page = 1;  	region = ib_umem_get(pd->uobject->context, start, length, acc, 0);  	if (IS_ERR(region)) { @@ -2348,8 +2346,10 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  	skip_pages = ((u32)region->offset) >> 12; -	if (ib_copy_from_udata(&req, udata, sizeof(req))) +	if (ib_copy_from_udata(&req, udata, sizeof(req))) { +		ib_umem_release(region);  		return ERR_PTR(-EFAULT); +	}  	nes_debug(NES_DBG_MR, "Memory Registration type = %08X.\n", req.reg_type);  	switch (req.reg_type) { @@ -2369,7 +2369,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  			next_stag_index %= nesadapter->max_mr;  			err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, -					nesadapter->max_mr, &stag_index, &next_stag_index); +					nesadapter->max_mr, &stag_index, &next_stag_index, NES_RESOURCE_USER_MR);  			if (err) {  				ib_umem_release(region);  				return ERR_PTR(err); @@ -2383,128 +2383,125 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  			}  			nesmr->region = region; -			list_for_each_entry(chunk, ®ion->chunk_list, list) { -				nes_debug(NES_DBG_MR, "Chunk: nents = %u, nmap = %u .\n", -						chunk->nents, chunk->nmap); -				for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) { -					if (sg_dma_address(&chunk->page_list[nmap_index]) & ~PAGE_MASK) { -						ib_umem_release(region); -						nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); -						nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n", -								(unsigned int) sg_dma_address(&chunk->page_list[nmap_index])); -						ibmr = ERR_PTR(-EINVAL); -						kfree(nesmr); -						goto reg_user_mr_err; -					} +			for_each_sg(region->sg_head.sgl, sg, region->nmap, entry) { +				if (sg_dma_address(sg) & ~PAGE_MASK) { +					ib_umem_release(region); +					nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); +					nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n", +						  (unsigned int) sg_dma_address(sg)); +					ibmr = ERR_PTR(-EINVAL); +					kfree(nesmr); +					goto reg_user_mr_err; +				} -					if (!sg_dma_len(&chunk->page_list[nmap_index])) { -						ib_umem_release(region); -						nes_free_resource(nesadapter, nesadapter->allocated_mrs, -								stag_index); -						nes_debug(NES_DBG_MR, "Invalid Buffer Size\n"); -						ibmr = ERR_PTR(-EINVAL); -						kfree(nesmr); -						goto reg_user_mr_err; -					} +				if (!sg_dma_len(sg)) { +					ib_umem_release(region); +					nes_free_resource(nesadapter, nesadapter->allocated_mrs, +							  stag_index); +					nes_debug(NES_DBG_MR, "Invalid Buffer Size\n"); +					ibmr = ERR_PTR(-EINVAL); +					kfree(nesmr); +					goto reg_user_mr_err; +				} -					region_length += sg_dma_len(&chunk->page_list[nmap_index]); -					chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12; -					region_length -= skip_pages << 12; -					for (page_index=skip_pages; page_index < chunk_pages; page_index++) { -						skip_pages = 0; -						if ((page_count!=0)&&(page_count<<12)-(region->offset&(4096-1))>=region->length) -							goto enough_pages; -						if ((page_count&0x01FF) == 0) { -							if (page_count >= 1024 * 512) { +				region_length += sg_dma_len(sg); +				chunk_pages = sg_dma_len(sg) >> 12; +				region_length -= skip_pages << 12; +				for (page_index = skip_pages; page_index < chunk_pages; page_index++) { +					skip_pages = 0; +					if ((page_count != 0) && (page_count<<12)-(region->offset&(4096-1)) >= region->length) +						goto enough_pages; +					if ((page_count&0x01FF) == 0) { +						if (page_count >= 1024 * 512) { +							ib_umem_release(region); +							nes_free_resource(nesadapter, +									  nesadapter->allocated_mrs, stag_index); +							kfree(nesmr); +							ibmr = ERR_PTR(-E2BIG); +							goto reg_user_mr_err; +						} +						if (root_pbl_index == 1) { +							root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, +									8192, &root_vpbl.pbl_pbase); +							nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n", +								  root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase); +							if (!root_vpbl.pbl_vbase) {  								ib_umem_release(region); -								nes_free_resource(nesadapter, -										nesadapter->allocated_mrs, stag_index); +								pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, +										    vpbl.pbl_pbase); +								nes_free_resource(nesadapter, nesadapter->allocated_mrs, +										  stag_index);  								kfree(nesmr); -								ibmr = ERR_PTR(-E2BIG); +								ibmr = ERR_PTR(-ENOMEM);  								goto reg_user_mr_err;  							} -							if (root_pbl_index == 1) { -								root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, -										8192, &root_vpbl.pbl_pbase); -								nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n", -										root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase); -								if (!root_vpbl.pbl_vbase) { -									ib_umem_release(region); -									pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, -											vpbl.pbl_pbase); -									nes_free_resource(nesadapter, nesadapter->allocated_mrs, -											stag_index); -									kfree(nesmr); -									ibmr = ERR_PTR(-ENOMEM); -									goto reg_user_mr_err; -								} -								root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, -										GFP_KERNEL); -								if (!root_vpbl.leaf_vpbl) { -									ib_umem_release(region); -									pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase, -											root_vpbl.pbl_pbase); -									pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, -											vpbl.pbl_pbase); -									nes_free_resource(nesadapter, nesadapter->allocated_mrs, -											stag_index); -									kfree(nesmr); -									ibmr = ERR_PTR(-ENOMEM); -									goto reg_user_mr_err; -								} -								root_vpbl.pbl_vbase[0].pa_low = -										cpu_to_le32((u32)vpbl.pbl_pbase); -								root_vpbl.pbl_vbase[0].pa_high = -										cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32))); -								root_vpbl.leaf_vpbl[0] = vpbl; -							} -							vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096, -									&vpbl.pbl_pbase); -							nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n", -									vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase); -							if (!vpbl.pbl_vbase) { +							root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, +									GFP_KERNEL); +							if (!root_vpbl.leaf_vpbl) {  								ib_umem_release(region); -								nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); -								ibmr = ERR_PTR(-ENOMEM); +								pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase, +										    root_vpbl.pbl_pbase); +								pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, +										    vpbl.pbl_pbase); +								nes_free_resource(nesadapter, nesadapter->allocated_mrs, +										  stag_index);  								kfree(nesmr); +								ibmr = ERR_PTR(-ENOMEM);  								goto reg_user_mr_err;  							} -							if (1 <= root_pbl_index) { -								root_vpbl.pbl_vbase[root_pbl_index].pa_low = -										cpu_to_le32((u32)vpbl.pbl_pbase); -								root_vpbl.pbl_vbase[root_pbl_index].pa_high = -										cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32))); -								root_vpbl.leaf_vpbl[root_pbl_index] = vpbl; -							} -							root_pbl_index++; -							cur_pbl_index = 0; +							root_vpbl.pbl_vbase[0].pa_low = +									cpu_to_le32((u32)vpbl.pbl_pbase); +							root_vpbl.pbl_vbase[0].pa_high = +									cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32))); +							root_vpbl.leaf_vpbl[0] = vpbl;  						} -						if (single_page) { -							if (page_count != 0) { -								if ((last_dma_addr+4096) != -										(sg_dma_address(&chunk->page_list[nmap_index])+ -										(page_index*4096))) -									single_page = 0; -								last_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+ -										(page_index*4096); -							} else { -								first_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+ -										(page_index*4096); -								last_dma_addr = first_dma_addr; -							} +						vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096, +								&vpbl.pbl_pbase); +						nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n", +							  vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase); +						if (!vpbl.pbl_vbase) { +							ib_umem_release(region); +							nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); +							ibmr = ERR_PTR(-ENOMEM); +							kfree(nesmr); +							goto reg_user_mr_err; +						} +						if (1 <= root_pbl_index) { +							root_vpbl.pbl_vbase[root_pbl_index].pa_low = +									cpu_to_le32((u32)vpbl.pbl_pbase); +							root_vpbl.pbl_vbase[root_pbl_index].pa_high = +									cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32))); +							root_vpbl.leaf_vpbl[root_pbl_index] = vpbl; +						} +						root_pbl_index++; +						cur_pbl_index = 0; +					} +					if (single_page) { +						if (page_count != 0) { +							if ((last_dma_addr+4096) != +									(sg_dma_address(sg)+ +									(page_index*4096))) +								single_page = 0; +							last_dma_addr = sg_dma_address(sg)+ +									(page_index*4096); +						} else { +							first_dma_addr = sg_dma_address(sg)+ +									(page_index*4096); +							last_dma_addr = first_dma_addr;  						} - -						vpbl.pbl_vbase[cur_pbl_index].pa_low = -								cpu_to_le32((u32)(sg_dma_address(&chunk->page_list[nmap_index])+ -								(page_index*4096))); -						vpbl.pbl_vbase[cur_pbl_index].pa_high = -								cpu_to_le32((u32)((((u64)(sg_dma_address(&chunk->page_list[nmap_index])+ -								(page_index*4096))) >> 32))); -						cur_pbl_index++; -						page_count++;  					} + +					vpbl.pbl_vbase[cur_pbl_index].pa_low = +							cpu_to_le32((u32)(sg_dma_address(sg)+ +							(page_index*4096))); +					vpbl.pbl_vbase[cur_pbl_index].pa_high = +							cpu_to_le32((u32)((((u64)(sg_dma_address(sg)+ +							(page_index*4096))) >> 32))); +					cur_pbl_index++; +					page_count++;  				}  			} +  			enough_pages:  			nes_debug(NES_DBG_MR, "calculating stag, stag_index=0x%08x, driver_key=0x%08x,"  					" stag_key=0x%08x\n", @@ -2568,6 +2565,11 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  			return ibmr;  		case IWNES_MEMREG_TYPE_QP:  		case IWNES_MEMREG_TYPE_CQ: +			if (!region->length) { +				nes_debug(NES_DBG_MR, "Unable to register zero length region for CQ\n"); +				ib_umem_release(region); +				return ERR_PTR(-EINVAL); +			}  			nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);  			if (!nespbl) {  				nes_debug(NES_DBG_MR, "Unable to allocate PBL\n"); @@ -2611,25 +2613,28 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  				  nespbl->pbl_size, (unsigned long) nespbl->pbl_pbase,  				  (void *) nespbl->pbl_vbase, nespbl->user_base); -			list_for_each_entry(chunk, ®ion->chunk_list, list) { -				for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) { -					chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12; -					chunk_pages += (sg_dma_len(&chunk->page_list[nmap_index]) & (4096-1)) ? 1 : 0; -					nespbl->page = sg_page(&chunk->page_list[0]); -					for (page_index=0; page_index<chunk_pages; page_index++) { -						((__le32 *)pbl)[0] = cpu_to_le32((u32) -								(sg_dma_address(&chunk->page_list[nmap_index])+ -								(page_index*4096))); -						((__le32 *)pbl)[1] = cpu_to_le32(((u64) -								(sg_dma_address(&chunk->page_list[nmap_index])+ -								(page_index*4096)))>>32); -						nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl, -								(unsigned long long)*pbl, -								le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0])); -						pbl++; -					} +			for_each_sg(region->sg_head.sgl, sg, region->nmap, entry) { +				chunk_pages = sg_dma_len(sg) >> 12; +				chunk_pages += (sg_dma_len(sg) & (4096-1)) ? 1 : 0; +				if (first_page) { +					nespbl->page = sg_page(sg); +					first_page = 0; +				} + +				for (page_index = 0; page_index < chunk_pages; page_index++) { +					((__le32 *)pbl)[0] = cpu_to_le32((u32) +							(sg_dma_address(sg)+ +							(page_index*4096))); +					((__le32 *)pbl)[1] = cpu_to_le32(((u64) +							(sg_dma_address(sg)+ +							(page_index*4096)))>>32); +					nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl, +						  (unsigned long long)*pbl, +						  le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0])); +					pbl++;  				}  			} +  			if (req.reg_type == IWNES_MEMREG_TYPE_QP) {  				list_add_tail(&nespbl->list, &nes_ucontext->qp_reg_mem_list);  			} else { @@ -2641,6 +2646,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,  			return &nesmr->ibmr;  	} +	ib_umem_release(region);  	return ERR_PTR(-ENOSYS);  } @@ -2831,7 +2837,7 @@ static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,  	init_attr->qp_context = nesqp->ibqp.qp_context;  	init_attr->send_cq = nesqp->ibqp.send_cq;  	init_attr->recv_cq = nesqp->ibqp.recv_cq; -	init_attr->srq = nesqp->ibqp.srq = nesqp->ibqp.srq; +	init_attr->srq = nesqp->ibqp.srq;  	init_attr->cap = attr->cap;  	return 0; @@ -3014,6 +3020,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,  					switch (nesqp->hw_iwarp_state) {  						case NES_AEQE_IWARP_STATE_CLOSING:  							next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING; +							break;  						case NES_AEQE_IWARP_STATE_TERMINATE:  							next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;  							break; @@ -3076,18 +3083,9 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,  		}  		nesqp->ibqp_state = attr->qp_state; -		if (((nesqp->iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == -				(u32)NES_CQP_QP_IWARP_STATE_RTS) && -				((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) > -				(u32)NES_CQP_QP_IWARP_STATE_RTS)) { -			nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK; -			nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n", -					nesqp->iwarp_state); -		} else { -			nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK; -			nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n", -					nesqp->iwarp_state); -		} +		nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK; +		nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n", +				nesqp->iwarp_state);  	}  	if (attr_mask & IB_QP_ACCESS_FLAGS) { @@ -3139,9 +3137,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,  				" original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",  				nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),  				original_last_aeq, nesqp->last_aeq); -		if ((!ret) || -				((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) && -				(ret))) { +		if (!ret || original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {  			if (dont_wait) {  				if (nesqp->cm_id && nesqp->hw_tcp_state != 0) {  					nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d)," @@ -3436,6 +3432,8 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,  					    NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX,  					    ib_wr->wr.fast_reg.length);  			set_wqe_32bit_value(wqe->wqe_words, +					    NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0); +			set_wqe_32bit_value(wqe->wqe_words,  					    NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX,  					    ib_wr->wr.fast_reg.rkey);  			/* Set page size: */ @@ -3732,7 +3730,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)  						entry->opcode = IB_WC_SEND;  						break;  					case NES_IWARP_SQ_OP_LOCINV: -						entry->opcode = IB_WR_LOCAL_INV; +						entry->opcode = IB_WC_LOCAL_INV;  						break;  					case NES_IWARP_SQ_OP_FAST_REG:  						entry->opcode = IB_WC_FAST_REG_MR; @@ -3882,7 +3880,6 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)  	nesibdev->ibdev.dev.parent = &nesdev->pcidev->dev;  	nesibdev->ibdev.query_device = nes_query_device;  	nesibdev->ibdev.query_port = nes_query_port; -	nesibdev->ibdev.modify_port = nes_modify_port;  	nesibdev->ibdev.query_pkey = nes_query_pkey;  	nesibdev->ibdev.query_gid = nes_query_gid;  	nesibdev->ibdev.alloc_ucontext = nes_alloc_ucontext; @@ -3936,6 +3933,30 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)  	return nesibdev;  } + +/** + * nes_handle_delayed_event + */ +static void nes_handle_delayed_event(unsigned long data) +{ +	struct nes_vnic *nesvnic = (void *) data; + +	if (nesvnic->delayed_event != nesvnic->last_dispatched_event) { +		struct ib_event event; + +		event.device = &nesvnic->nesibdev->ibdev; +		if (!event.device) +			goto stop_timer; +		event.event = nesvnic->delayed_event; +		event.element.port_num = nesvnic->logical_port + 1; +		ib_dispatch_event(&event); +	} + +stop_timer: +	nesvnic->event_timer.function = NULL; +} + +  void  nes_port_ibevent(struct nes_vnic *nesvnic)  {  	struct nes_ib_device *nesibdev = nesvnic->nesibdev; @@ -3944,7 +3965,18 @@ void  nes_port_ibevent(struct nes_vnic *nesvnic)  	event.device = &nesibdev->ibdev;  	event.element.port_num = nesvnic->logical_port + 1;  	event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; -	ib_dispatch_event(&event); + +	if (!nesvnic->event_timer.function) { +		ib_dispatch_event(&event); +		nesvnic->last_dispatched_event = event.event; +		nesvnic->event_timer.function = nes_handle_delayed_event; +		nesvnic->event_timer.data = (unsigned long) nesvnic; +		nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY; +		add_timer(&nesvnic->event_timer); +	} else { +		mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY); +	} +	nesvnic->delayed_event = event.event;  } diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 2df9993e0ca..309b31c31ae 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation.  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 @@ -139,7 +139,8 @@ struct nes_qp {  	struct nes_cq         *nesrcq;  	struct nes_pd         *nespd;  	void *cm_node; /* handle of the node this QP is associated with */ -	struct ietf_mpa_frame *ietf_frame; +	void                  *ietf_frame; +	u8                    ietf_frame_size;  	dma_addr_t            ietf_frame_pbase;  	struct ib_mr          *lsmm_mr;  	struct nes_hw_qp      hwqp; @@ -154,6 +155,7 @@ struct nes_qp {  	u32                   mmap_sq_db_index;  	u32                   mmap_rq_db_index;  	spinlock_t            lock; +	spinlock_t            pau_lock;  	struct nes_qp_context *nesqp_context;  	dma_addr_t            nesqp_context_pbase;  	void	              *pbl_vbase; @@ -161,6 +163,8 @@ struct nes_qp {  	struct page           *page;  	struct timer_list     terminate_timer;  	enum ib_event_type    terminate_eventtype; +	struct sk_buff_head   pau_list; +	u32                   pau_rcv_nxt;  	u16                   active_conn:1;  	u16                   skip_lsmm:1;  	u16                   user_mode:1; @@ -168,7 +172,8 @@ struct nes_qp {  	u16                   flush_issued:1;  	u16                   destroyed:1;  	u16                   sig_all:1; -	u16                   rsvd:9; +	u16                   pau_mode:1; +	u16                   rsvd:8;  	u16                   private_data_len;  	u16                   term_sq_flush_code;  	u16                   term_rq_flush_code; @@ -176,5 +181,9 @@ struct nes_qp {  	u8                    hw_tcp_state;  	u8                    term_flags;  	u8                    sq_kmapped; +	u8                    pau_busy; +	u8                    pau_pending; +	u8                    pau_state; +	__u64                 nesuqp_addr;  };  #endif			/* NES_VERBS_H */  | 
