diff mbox

[RFC,1/6] qed: Add support for hardware offloaded iSCSI.

Message ID 1476853273-22960-2-git-send-email-manish.rangankar@cavium.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

manish.rangankar@cavium.com Oct. 19, 2016, 5:01 a.m. UTC
From: Yuval Mintz <Yuval.Mintz@qlogic.com>

This adds the backbone required for the various HW initalizations
which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
4xxxx line of adapters - FW notification, resource initializations, etc.

Signed-off-by: Arun Easi <arun.easi@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
---
 drivers/net/ethernet/qlogic/Kconfig            |   15 +
 drivers/net/ethernet/qlogic/qed/Makefile       |    1 +
 drivers/net/ethernet/qlogic/qed/qed.h          |    8 +-
 drivers/net/ethernet/qlogic/qed/qed_dev.c      |   15 +
 drivers/net/ethernet/qlogic/qed/qed_int.h      |    1 -
 drivers/net/ethernet/qlogic/qed/qed_iscsi.c    | 1310 ++++++++++++++++++++++++
 drivers/net/ethernet/qlogic/qed/qed_iscsi.h    |   52 +
 drivers/net/ethernet/qlogic/qed/qed_l2.c       |    1 -
 drivers/net/ethernet/qlogic/qed/qed_ll2.c      |   35 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c     |    2 -
 drivers/net/ethernet/qlogic/qed/qed_mcp.h      |    6 -
 drivers/net/ethernet/qlogic/qed/qed_reg_addr.h |    2 +
 drivers/net/ethernet/qlogic/qed/qed_spq.c      |   15 +
 include/linux/qed/qed_if.h                     |    2 +
 include/linux/qed/qed_iscsi_if.h               |  249 +++++
 15 files changed, 1692 insertions(+), 22 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
 create mode 100644 include/linux/qed/qed_iscsi_if.h

Comments

Hannes Reinecke Oct. 19, 2016, 7:31 a.m. UTC | #1
On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> From: Yuval Mintz <Yuval.Mintz@qlogic.com>
> 
> This adds the backbone required for the various HW initalizations
> which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
> 4xxxx line of adapters - FW notification, resource initializations, etc.
> 
> Signed-off-by: Arun Easi <arun.easi@cavium.com>
> Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
> ---
>  drivers/net/ethernet/qlogic/Kconfig            |   15 +
>  drivers/net/ethernet/qlogic/qed/Makefile       |    1 +
>  drivers/net/ethernet/qlogic/qed/qed.h          |    8 +-
>  drivers/net/ethernet/qlogic/qed/qed_dev.c      |   15 +
>  drivers/net/ethernet/qlogic/qed/qed_int.h      |    1 -
>  drivers/net/ethernet/qlogic/qed/qed_iscsi.c    | 1310 ++++++++++++++++++++++++
>  drivers/net/ethernet/qlogic/qed/qed_iscsi.h    |   52 +
>  drivers/net/ethernet/qlogic/qed/qed_l2.c       |    1 -
>  drivers/net/ethernet/qlogic/qed/qed_ll2.c      |   35 +-
>  drivers/net/ethernet/qlogic/qed/qed_main.c     |    2 -
>  drivers/net/ethernet/qlogic/qed/qed_mcp.h      |    6 -
>  drivers/net/ethernet/qlogic/qed/qed_reg_addr.h |    2 +
>  drivers/net/ethernet/qlogic/qed/qed_spq.c      |   15 +
>  include/linux/qed/qed_if.h                     |    2 +
>  include/linux/qed/qed_iscsi_if.h               |  249 +++++
>  15 files changed, 1692 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
>  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
>  create mode 100644 include/linux/qed/qed_iscsi_if.h
> 
> diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
> index 0df1391f9..bad4fae 100644
> --- a/drivers/net/ethernet/qlogic/Kconfig
> +++ b/drivers/net/ethernet/qlogic/Kconfig
> @@ -118,4 +118,19 @@ config INFINIBAND_QEDR
>  	  for QLogic QED. This would be replaced by the 'real' option
>  	  once the QEDR driver is added [+relocated].
>  
> +config QED_ISCSI
> +	bool
> +
> +config QEDI
> +	tristate "QLogic QED 25/40/100Gb iSCSI driver"
> +	depends on QED
> +	select QED_LL2
> +	select QED_ISCSI
> +	default n
> +	---help---
> +	  This provides a temporary node that allows the compilation
> +	  and logical testing of the hardware offload iSCSI support
> +	  for QLogic QED. This would be replaced by the 'real' option
> +	  once the QEDI driver is added [+relocated].
> +
>  endif # NET_VENDOR_QLOGIC
> diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
> index cda0af7..b76669c 100644
> --- a/drivers/net/ethernet/qlogic/qed/Makefile
> +++ b/drivers/net/ethernet/qlogic/qed/Makefile
> @@ -6,3 +6,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
>  qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
>  qed-$(CONFIG_QED_LL2) += qed_ll2.o
>  qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
> +qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
> diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
> index 653bb57..a61b1c0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed.h
> @@ -35,6 +35,7 @@
>  
>  #define QED_WFQ_UNIT	100
>  
> +#define ISCSI_BDQ_ID(_port_id) (_port_id)
>  #define QED_WID_SIZE            (1024)
>  #define QED_PF_DEMS_SIZE        (4)
>  
> @@ -167,6 +168,7 @@ enum QED_RESOURCES {
>  	QED_ILT,
>  	QED_LL2_QUEUE,
>  	QED_RDMA_STATS_QUEUE,
> +	QED_CMDQS_CQS,
>  	QED_MAX_RESC,
>  };
>  
> @@ -379,6 +381,7 @@ struct qed_hwfn {
>  	bool				using_ll2;
>  	struct qed_ll2_info		*p_ll2_info;
>  	struct qed_rdma_info		*p_rdma_info;
> +	struct qed_iscsi_info		*p_iscsi_info;
>  	struct qed_pf_params		pf_params;
>  
>  	bool b_rdma_enabled_in_prs;
> @@ -578,6 +581,8 @@ struct qed_dev {
>  	/* Linux specific here */
>  	struct  qede_dev		*edev;
>  	struct  pci_dev			*pdev;
> +	u32 flags;
> +#define QED_FLAG_STORAGE_STARTED	(BIT(0))
>  	int				msg_enable;
>  
>  	struct pci_params		pci_params;
> @@ -591,6 +596,7 @@ struct qed_dev {
>  	union {
>  		struct qed_common_cb_ops	*common;
>  		struct qed_eth_cb_ops		*eth;
> +		struct qed_iscsi_cb_ops		*iscsi;
>  	} protocol_ops;
>  	void				*ops_cookie;
>  
> @@ -600,7 +606,7 @@ struct qed_dev {
>  	struct qed_cb_ll2_info		*ll2;
>  	u8				ll2_mac_address[ETH_ALEN];
>  #endif
> -
> +	DECLARE_HASHTABLE(connections, 10);
>  	const struct firmware		*firmware;
>  
>  	u32 rdma_max_sge;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> index 754f6a9..a4234c0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> @@ -29,6 +29,7 @@
>  #include "qed_hw.h"
>  #include "qed_init_ops.h"
>  #include "qed_int.h"
> +#include "qed_iscsi.h"
>  #include "qed_ll2.h"
>  #include "qed_mcp.h"
>  #include "qed_reg_addr.h"
> @@ -155,6 +156,9 @@ void qed_resc_free(struct qed_dev *cdev)
>  #ifdef CONFIG_QED_LL2
>  		qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info);
>  #endif
> +		if (IS_ENABLED(CONFIG_QEDI) &&
> +				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> +			qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);
>  		qed_iov_free(p_hwfn);
>  		qed_dmae_info_free(p_hwfn);
>  		qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
> @@ -411,6 +415,7 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
>  
>  int qed_resc_alloc(struct qed_dev *cdev)
>  {
> +	struct qed_iscsi_info *p_iscsi_info;
>  #ifdef CONFIG_QED_LL2
>  	struct qed_ll2_info *p_ll2_info;
>  #endif
> @@ -532,6 +537,13 @@ int qed_resc_alloc(struct qed_dev *cdev)
>  			p_hwfn->p_ll2_info = p_ll2_info;
>  		}
>  #endif
> +		if (IS_ENABLED(CONFIG_QEDI) &&
> +			p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
> +			p_iscsi_info = qed_iscsi_alloc(p_hwfn);
> +			if (!p_iscsi_info)
> +				goto alloc_no_mem;
> +			p_hwfn->p_iscsi_info = p_iscsi_info;
> +		}
>  
>  		/* DMA info initialization */
>  		rc = qed_dmae_info_alloc(p_hwfn);
> @@ -585,6 +597,9 @@ void qed_resc_setup(struct qed_dev *cdev)
>  		if (p_hwfn->using_ll2)
>  			qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info);
>  #endif
> +		if (IS_ENABLED(CONFIG_QEDI) &&
> +				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> +			qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info);
>  	}
>  }
>  
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h
> index 0948be6..cc28066 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_int.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h
> @@ -218,7 +218,6 @@ struct qed_igu_info {
>  	u16			free_blks;
>  };
>  
> -/* TODO Names of function may change... */
>  void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn,
>  			      struct qed_ptt *p_ptt,
>  			      bool b_set,
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> new file mode 100644
> index 0000000..cb22dad
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> @@ -0,0 +1,1310 @@
> +/* QLogic qed NIC Driver

Shouldn't that be qedi iSCSI Driver?

> + * Copyright (c) 2015 QLogic Corporation
> + *
> + * This software is available 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.
> + */
> +
> +#include <linux/types.h>
> +#include <asm/byteorder.h>
> +#include <asm/param.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/etherdevice.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/stddef.h>
> +#include <linux/string.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/qed/qed_iscsi_if.h>
> +#include "qed.h"
> +#include "qed_cxt.h"
> +#include "qed_dev_api.h"
> +#include "qed_hsi.h"
> +#include "qed_hw.h"
> +#include "qed_int.h"
> +#include "qed_iscsi.h"
> +#include "qed_ll2.h"
> +#include "qed_mcp.h"
> +#include "qed_sp.h"
> +#include "qed_sriov.h"
> +#include "qed_reg_addr.h"
> +
> +struct qed_iscsi_conn {
> +	struct list_head list_entry;
> +	bool free_on_delete;
> +
> +	u16 conn_id;
> +	u32 icid;
> +	u32 fw_cid;
> +
> +	u8 layer_code;
> +	u8 offl_flags;
> +	u8 connect_mode;
> +	u32 initial_ack;
> +	dma_addr_t sq_pbl_addr;
> +	struct qed_chain r2tq;
> +	struct qed_chain xhq;
> +	struct qed_chain uhq;
> +
> +	struct tcp_upload_params *tcp_upload_params_virt_addr;
> +	dma_addr_t tcp_upload_params_phys_addr;
> +	struct scsi_terminate_extra_params *queue_cnts_virt_addr;
> +	dma_addr_t queue_cnts_phys_addr;
> +	dma_addr_t syn_phy_addr;
> +
> +	u16 syn_ip_payload_length;
> +	u8 local_mac[6];
> +	u8 remote_mac[6];
> +	u16 vlan_id;
> +	u8 tcp_flags;
> +	u8 ip_version;
> +	u32 remote_ip[4];
> +	u32 local_ip[4];
> +	u8 ka_max_probe_cnt;
> +	u8 dup_ack_theshold;
> +	u32 rcv_next;
> +	u32 snd_una;
> +	u32 snd_next;
> +	u32 snd_max;
> +	u32 snd_wnd;
> +	u32 rcv_wnd;
> +	u32 snd_wl1;
> +	u32 cwnd;
> +	u32 ss_thresh;
> +	u16 srtt;
> +	u16 rtt_var;
> +	u32 ts_time;
> +	u32 ts_recent;
> +	u32 ts_recent_age;
> +	u32 total_rt;
> +	u32 ka_timeout_delta;
> +	u32 rt_timeout_delta;
> +	u8 dup_ack_cnt;
> +	u8 snd_wnd_probe_cnt;
> +	u8 ka_probe_cnt;
> +	u8 rt_cnt;
> +	u32 flow_label;
> +	u32 ka_timeout;
> +	u32 ka_interval;
> +	u32 max_rt_time;
> +	u32 initial_rcv_wnd;
> +	u8 ttl;
> +	u8 tos_or_tc;
> +	u16 remote_port;
> +	u16 local_port;
> +	u16 mss;
> +	u8 snd_wnd_scale;
> +	u8 rcv_wnd_scale;
> +	u32 ts_ticks_per_second;
> +	u16 da_timeout_value;
> +	u8 ack_frequency;
> +
> +	u8 update_flag;
> +	u8 default_cq;
> +	u32 max_seq_size;
> +	u32 max_recv_pdu_length;
> +	u32 max_send_pdu_length;
> +	u32 first_seq_length;
> +	u32 exp_stat_sn;
> +	u32 stat_sn;
> +	u16 physical_q0;
> +	u16 physical_q1;
> +	u8 abortive_dsconnect;
> +};
> +
> +static int
> +qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
> +			enum spq_mode comp_mode,
> +			struct qed_spq_comp_cb *p_comp_addr,
> +			void *event_context, iscsi_event_cb_t async_event_cb)
> +{
> +	struct iscsi_init_ramrod_params *p_ramrod = NULL;
> +	struct scsi_init_func_queues *p_queue = NULL;
> +	struct qed_iscsi_pf_params *p_params = NULL;
> +	struct iscsi_spe_func_init *p_init = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	int rc = 0;
> +	u32 dval;
> +	u16 val;
> +	u8 i;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = qed_spq_get_cid(p_hwfn);
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_INIT_FUNC,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_init;
> +	p_init = &p_ramrod->iscsi_init_spe;
> +	p_params = &p_hwfn->pf_params.iscsi_pf_params;
> +	p_queue = &p_init->q_params;
> +
> +	SET_FIELD(p_init->hdr.flags,
> +		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, ISCSI_SLOW_PATH_LAYER_CODE);
> +	p_init->hdr.op_code = ISCSI_RAMROD_CMD_ID_INIT_FUNC;
> +
> +	val = p_params->half_way_close_timeout;
> +	p_init->half_way_close_timeout = cpu_to_le16(val);
> +	p_init->num_sq_pages_in_ring = p_params->num_sq_pages_in_ring;
> +	p_init->num_r2tq_pages_in_ring = p_params->num_r2tq_pages_in_ring;
> +	p_init->num_uhq_pages_in_ring = p_params->num_uhq_pages_in_ring;
> +	p_init->func_params.log_page_size = p_params->log_page_size;
> +	val = p_params->num_tasks;
> +	p_init->func_params.num_tasks = cpu_to_le16(val);
> +	p_init->debug_mode.flags = p_params->debug_mode;
> +
> +	DMA_REGPAIR_LE(p_queue->glbl_q_params_addr,
> +		       p_params->glbl_q_params_addr);
> +
> +	val = p_params->cq_num_entries;
> +	p_queue->cq_num_entries = cpu_to_le16(val);
> +	val = p_params->cmdq_num_entries;
> +	p_queue->cmdq_num_entries = cpu_to_le16(val);
> +	p_queue->num_queues = p_params->num_queues;
> +	dval = (u8)p_hwfn->hw_info.resc_start[QED_CMDQS_CQS];
> +	p_queue->queue_relative_offset = (u8)dval;
> +	p_queue->cq_sb_pi = p_params->gl_rq_pi;
> +	p_queue->cmdq_sb_pi = p_params->gl_cmd_pi;
> +
> +	for (i = 0; i < p_params->num_queues; i++) {
> +		val = p_hwfn->sbs_info[i]->igu_sb_id;
> +		p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val);
> +	}
> +
> +	p_queue->bdq_resource_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> +	DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_RQ],
> +		       p_params->bdq_pbl_base_addr[BDQ_ID_RQ]);
> +	p_queue->bdq_pbl_num_entries[BDQ_ID_RQ] =
> +	    p_params->bdq_pbl_num_entries[BDQ_ID_RQ];
> +	val = p_params->bdq_xoff_threshold[BDQ_ID_RQ];
> +	p_queue->bdq_xoff_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
> +	val = p_params->bdq_xon_threshold[BDQ_ID_RQ];
> +	p_queue->bdq_xon_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
> +
> +	DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_IMM_DATA],
> +		       p_params->bdq_pbl_base_addr[BDQ_ID_IMM_DATA]);
> +	p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA] =
> +	    p_params->bdq_pbl_num_entries[BDQ_ID_IMM_DATA];
> +	val = p_params->bdq_xoff_threshold[BDQ_ID_IMM_DATA];
> +	p_queue->bdq_xoff_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
> +	val = p_params->bdq_xon_threshold[BDQ_ID_IMM_DATA];
> +	p_queue->bdq_xon_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
> +	val = p_params->rq_buffer_size;
> +	p_queue->rq_buffer_size = cpu_to_le16(val);
> +	if (p_params->is_target) {
> +		SET_FIELD(p_queue->q_validity,
> +			  SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> +		if (p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA])
> +			SET_FIELD(p_queue->q_validity,
> +				  SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID, 1);
> +		SET_FIELD(p_queue->q_validity,
> +			  SCSI_INIT_FUNC_QUEUES_CMD_VALID, 1);
> +	} else {
> +		SET_FIELD(p_queue->q_validity,
> +			  SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> +	}
> +	p_ramrod->tcp_init.two_msl_timer = cpu_to_le32(p_params->two_msl_timer);
> +	val = p_params->tx_sws_timer;
> +	p_ramrod->tcp_init.tx_sws_timer = cpu_to_le16(val);
> +	p_ramrod->tcp_init.maxfinrt = p_params->max_fin_rt;
> +
> +	p_hwfn->p_iscsi_info->event_context = event_context;
> +	p_hwfn->p_iscsi_info->event_cb = async_event_cb;
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn,
> +				     struct qed_iscsi_conn *p_conn,
> +				     enum spq_mode comp_mode,
> +				     struct qed_spq_comp_cb *p_comp_addr)
> +{
> +	struct iscsi_spe_conn_offload *p_ramrod = NULL;
> +	struct tcp_offload_params_opt2 *p_tcp2 = NULL;
> +	struct tcp_offload_params *p_tcp = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	union qed_qm_pq_params pq_params;
> +	u16 pq0_id = 0, pq1_id = 0;
> +	dma_addr_t r2tq_pbl_addr;
> +	dma_addr_t xhq_pbl_addr;
> +	dma_addr_t uhq_pbl_addr;
> +	int rc = 0;
> +	u32 dval;
> +	u16 wval;
> +	u8 ucval;
> +	u8 i;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = p_conn->icid;
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_conn_offload;
> +
> +	/* Transmission PQ is the first of the PF */
> +	memset(&pq_params, 0, sizeof(pq_params));
> +	pq0_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> +	p_conn->physical_q0 = cpu_to_le16(pq0_id);
> +	p_ramrod->iscsi.physical_q0 = cpu_to_le16(pq0_id);
> +
> +	/* iSCSI Pure-ACK PQ */
> +	pq_params.iscsi.q_idx = 1;
> +	pq1_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> +	p_conn->physical_q1 = cpu_to_le16(pq1_id);
> +	p_ramrod->iscsi.physical_q1 = cpu_to_le16(pq1_id);
> +
> +	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN;
> +	SET_FIELD(p_ramrod->hdr.flags, ISCSI_SLOW_PATH_HDR_LAYER_CODE,
> +		  p_conn->layer_code);
> +
> +	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> +	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> +
> +	DMA_REGPAIR_LE(p_ramrod->iscsi.sq_pbl_addr, p_conn->sq_pbl_addr);
> +
> +	r2tq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->r2tq);
> +	DMA_REGPAIR_LE(p_ramrod->iscsi.r2tq_pbl_addr, r2tq_pbl_addr);
> +
> +	xhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->xhq);
> +	DMA_REGPAIR_LE(p_ramrod->iscsi.xhq_pbl_addr, xhq_pbl_addr);
> +
> +	uhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->uhq);
> +	DMA_REGPAIR_LE(p_ramrod->iscsi.uhq_pbl_addr, uhq_pbl_addr);
> +
> +	p_ramrod->iscsi.initial_ack = cpu_to_le32(p_conn->initial_ack);
> +	p_ramrod->iscsi.flags = p_conn->offl_flags;
> +	p_ramrod->iscsi.default_cq = p_conn->default_cq;
> +	p_ramrod->iscsi.stat_sn = cpu_to_le32(p_conn->stat_sn);
> +
> +	if (!GET_FIELD(p_ramrod->iscsi.flags,
> +		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> +		p_tcp = &p_ramrod->tcp;
> +		ucval = p_conn->local_mac[1];
> +		((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->local_mac[0];
> +		((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->local_mac[3];
> +		((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->local_mac[2];
> +		((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->local_mac[5];
> +		((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->local_mac[4];
> +		((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
> +		ucval = p_conn->remote_mac[1];
> +		((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->remote_mac[0];
> +		((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->remote_mac[3];
> +		((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->remote_mac[2];
> +		((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->remote_mac[5];
> +		((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->remote_mac[4];
> +		((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
> +
This looks terribly like endianness swapping. You sure this is
applicable for all architecture and endianness settings?
And wouldn't it be better to use one of the get_unaligned_XXX functions
here?

> +		p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
> +
> +		p_tcp->flags = p_conn->tcp_flags;
> +		p_tcp->ip_version = p_conn->ip_version;
> +		for (i = 0; i < 4; i++) {
> +			dval = p_conn->remote_ip[i];
> +			p_tcp->remote_ip[i] = cpu_to_le32(dval);
> +			dval = p_conn->local_ip[i];
> +			p_tcp->local_ip[i] = cpu_to_le32(dval);
> +		}
> +		p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
> +		p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
> +
> +		p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
> +		p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
> +		p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
> +		p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
> +		p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
> +		p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
> +		p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
> +		p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
> +		p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
> +		p_tcp->srtt = cpu_to_le16(p_conn->srtt);
> +		p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
> +		p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
> +		p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
> +		p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
> +		p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
> +		dval = p_conn->ka_timeout_delta;
> +		p_tcp->ka_timeout_delta = cpu_to_le32(dval);
> +		dval = p_conn->rt_timeout_delta;
> +		p_tcp->rt_timeout_delta = cpu_to_le32(dval);
> +		p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
> +		p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
> +		p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
> +		p_tcp->rt_cnt = p_conn->rt_cnt;
> +		p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
> +		p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
> +		p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
> +		p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
> +		dval = p_conn->initial_rcv_wnd;
> +		p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
> +		p_tcp->ttl = p_conn->ttl;
> +		p_tcp->tos_or_tc = p_conn->tos_or_tc;
> +		p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
> +		p_tcp->local_port = cpu_to_le16(p_conn->local_port);
> +		p_tcp->mss = cpu_to_le16(p_conn->mss);
> +		p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
> +		p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> +		dval = p_conn->ts_ticks_per_second;
> +		p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
> +		wval = p_conn->da_timeout_value;
> +		p_tcp->da_timeout_value = cpu_to_le16(wval);
> +		p_tcp->ack_frequency = p_conn->ack_frequency;
> +		p_tcp->connect_mode = p_conn->connect_mode;
> +	} else {
> +		p_tcp2 =
> +		    &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
> +		ucval = p_conn->local_mac[1];
> +		((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->local_mac[0];
> +		((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->local_mac[3];
> +		((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->local_mac[2];
> +		((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->local_mac[5];
> +		((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->local_mac[4];
> +		((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
> +
> +		ucval = p_conn->remote_mac[1];
> +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->remote_mac[0];
> +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->remote_mac[3];
> +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->remote_mac[2];
> +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->remote_mac[5];
> +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->remote_mac[4];
> +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
> +
Same here.

> +		p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);
> +		p_tcp2->flags = p_conn->tcp_flags;
> +
> +		p_tcp2->ip_version = p_conn->ip_version;
> +		for (i = 0; i < 4; i++) {
> +			dval = p_conn->remote_ip[i];
> +			p_tcp2->remote_ip[i] = cpu_to_le32(dval);
> +			dval = p_conn->local_ip[i];
> +			p_tcp2->local_ip[i] = cpu_to_le32(dval);
> +		}
> +
> +		p_tcp2->flow_label = cpu_to_le32(p_conn->flow_label);
> +		p_tcp2->ttl = p_conn->ttl;
> +		p_tcp2->tos_or_tc = p_conn->tos_or_tc;
> +		p_tcp2->remote_port = cpu_to_le16(p_conn->remote_port);
> +		p_tcp2->local_port = cpu_to_le16(p_conn->local_port);
> +		p_tcp2->mss = cpu_to_le16(p_conn->mss);
> +		p_tcp2->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> +		p_tcp2->connect_mode = p_conn->connect_mode;
> +		wval = p_conn->syn_ip_payload_length;
> +		p_tcp2->syn_ip_payload_length = cpu_to_le16(wval);
> +		p_tcp2->syn_phy_addr_lo = DMA_LO_LE(p_conn->syn_phy_addr);
> +		p_tcp2->syn_phy_addr_hi = DMA_HI_LE(p_conn->syn_phy_addr);
> +	}
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
> +				    struct qed_iscsi_conn *p_conn,
> +				    enum spq_mode comp_mode,
> +				    struct qed_spq_comp_cb *p_comp_addr)
> +{
> +	struct iscsi_conn_update_ramrod_params *p_ramrod = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	int rc = -EINVAL;
> +	u32 dval;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = p_conn->icid;
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_conn_update;
> +	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_UPDATE_CONN;
> +	SET_FIELD(p_ramrod->hdr.flags,
> +		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> +	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> +	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> +	p_ramrod->flags = p_conn->update_flag;
> +	p_ramrod->max_seq_size = cpu_to_le32(p_conn->max_seq_size);
> +	dval = p_conn->max_recv_pdu_length;
> +	p_ramrod->max_recv_pdu_length = cpu_to_le32(dval);
> +	dval = p_conn->max_send_pdu_length;
> +	p_ramrod->max_send_pdu_length = cpu_to_le32(dval);
> +	dval = p_conn->first_seq_length;
> +	p_ramrod->first_seq_length = cpu_to_le32(dval);
> +	p_ramrod->exp_stat_sn = cpu_to_le32(p_conn->exp_stat_sn);
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn,
> +				       struct qed_iscsi_conn *p_conn,
> +				       enum spq_mode comp_mode,
> +				       struct qed_spq_comp_cb *p_comp_addr)
> +{
> +	struct iscsi_spe_conn_termination *p_ramrod = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	int rc = -EINVAL;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = p_conn->icid;
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_TERMINATION_CONN,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_conn_terminate;
> +	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_TERMINATION_CONN;
> +	SET_FIELD(p_ramrod->hdr.flags,
> +		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> +	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> +	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> +	p_ramrod->abortive = p_conn->abortive_dsconnect;
> +
> +	DMA_REGPAIR_LE(p_ramrod->query_params_addr,
> +		       p_conn->tcp_upload_params_phys_addr);
> +	DMA_REGPAIR_LE(p_ramrod->queue_cnts_addr, p_conn->queue_cnts_phys_addr);
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_clear_sq(struct qed_hwfn *p_hwfn,
> +				      struct qed_iscsi_conn *p_conn,
> +				      enum spq_mode comp_mode,
> +				      struct qed_spq_comp_cb *p_comp_addr)
> +{
> +	struct iscsi_slow_path_hdr *p_ramrod = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	int rc = -EINVAL;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = p_conn->icid;
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_CLEAR_SQ,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_empty;
> +	p_ramrod->op_code = ISCSI_RAMROD_CMD_ID_CLEAR_SQ;
> +	SET_FIELD(p_ramrod->flags,
> +		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_func_stop(struct qed_hwfn *p_hwfn,
> +				  enum spq_mode comp_mode,
> +				  struct qed_spq_comp_cb *p_comp_addr)
> +{
> +	struct iscsi_spe_func_dstry *p_ramrod = NULL;
> +	struct qed_spq_entry *p_ent = NULL;
> +	struct qed_sp_init_data init_data;
> +	int rc = 0;
> +
> +	/* Get SPQ entry */
> +	memset(&init_data, 0, sizeof(init_data));
> +	init_data.cid = qed_spq_get_cid(p_hwfn);
> +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> +	init_data.comp_mode = comp_mode;
> +	init_data.p_comp_data = p_comp_addr;
> +
> +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> +				 ISCSI_RAMROD_CMD_ID_DESTROY_FUNC,
> +				 PROTOCOLID_ISCSI, &init_data);
> +	if (rc)
> +		return rc;
> +
> +	p_ramrod = &p_ent->ramrod.iscsi_destroy;
> +	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_DESTROY_FUNC;
> +
> +	return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
> +{
> +	return (u8 __iomem *)p_hwfn->doorbells +
> +			     qed_db_addr(cid, DQ_DEMS_LEGACY);
> +}
> +
> +static void __iomem *qed_iscsi_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
> +						    u8 bdq_id)
> +{
> +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
> +			     MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> +							     bdq_id);
> +}
> +
> +static void __iomem *qed_iscsi_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
> +						      u8 bdq_id)
> +{
> +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
> +			     TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> +							     bdq_id);
> +}
> +
> +static int qed_iscsi_setup_connection(struct qed_hwfn *p_hwfn,
> +				      struct qed_iscsi_conn *p_conn)
> +{
> +	if (!p_conn->queue_cnts_virt_addr)
> +		goto nomem;
> +	memset(p_conn->queue_cnts_virt_addr, 0,
> +	       sizeof(*p_conn->queue_cnts_virt_addr));
> +
> +	if (!p_conn->tcp_upload_params_virt_addr)
> +		goto nomem;
> +	memset(p_conn->tcp_upload_params_virt_addr, 0,
> +	       sizeof(*p_conn->tcp_upload_params_virt_addr));
> +
> +	if (!p_conn->r2tq.p_virt_addr)
> +		goto nomem;
> +	qed_chain_pbl_zero_mem(&p_conn->r2tq);
> +
> +	if (!p_conn->uhq.p_virt_addr)
> +		goto nomem;
> +	qed_chain_pbl_zero_mem(&p_conn->uhq);
> +
> +	if (!p_conn->xhq.p_virt_addr)
> +		goto nomem;
> +	qed_chain_pbl_zero_mem(&p_conn->xhq);
> +
> +	return 0;
> +nomem:
> +	return -ENOMEM;
> +}
> +
> +static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn,
> +					 struct qed_iscsi_conn **p_out_conn)
> +{
> +	u16 uhq_num_elements = 0, xhq_num_elements = 0, r2tq_num_elements = 0;
> +	struct scsi_terminate_extra_params *p_q_cnts = NULL;
> +	struct qed_iscsi_pf_params *p_params = NULL;
> +	struct tcp_upload_params *p_tcp = NULL;
> +	struct qed_iscsi_conn *p_conn = NULL;
> +	int rc = 0;
> +
> +	/* Try finding a free connection that can be used */
> +	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> +	if (!list_empty(&p_hwfn->p_iscsi_info->free_list))
> +		p_conn = list_first_entry(&p_hwfn->p_iscsi_info->free_list,
> +					  struct qed_iscsi_conn, list_entry);
> +	if (p_conn) {
> +		list_del(&p_conn->list_entry);
> +		spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +		*p_out_conn = p_conn;
> +		return 0;
> +	}
> +	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +
> +	/* Need to allocate a new connection */
> +	p_params = &p_hwfn->pf_params.iscsi_pf_params;
> +
> +	p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL);
> +	if (!p_conn)
> +		return -ENOMEM;
> +
> +	p_q_cnts = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> +				      sizeof(*p_q_cnts),
> +				      &p_conn->queue_cnts_phys_addr,
> +				      GFP_KERNEL);
> +	if (!p_q_cnts)
> +		goto nomem_queue_cnts_param;
> +	p_conn->queue_cnts_virt_addr = p_q_cnts;
> +
> +	p_tcp = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> +				   sizeof(*p_tcp),
> +				   &p_conn->tcp_upload_params_phys_addr,
> +				   GFP_KERNEL);
> +	if (!p_tcp)
> +		goto nomem_upload_param;
> +	p_conn->tcp_upload_params_virt_addr = p_tcp;
> +
> +	r2tq_num_elements = p_params->num_r2tq_pages_in_ring *
> +			    QED_CHAIN_PAGE_SIZE / 0x80;
> +	rc = qed_chain_alloc(p_hwfn->cdev,
> +			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> +			     QED_CHAIN_MODE_PBL,
> +			     QED_CHAIN_CNT_TYPE_U16,
> +			     r2tq_num_elements, 0x80, &p_conn->r2tq);
> +	if (rc)
> +		goto nomem_r2tq;
> +
> +	uhq_num_elements = p_params->num_uhq_pages_in_ring *
> +			   QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_uhqe);
> +	rc = qed_chain_alloc(p_hwfn->cdev,
> +			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> +			     QED_CHAIN_MODE_PBL,
> +			     QED_CHAIN_CNT_TYPE_U16,
> +			     uhq_num_elements,
> +			     sizeof(struct iscsi_uhqe), &p_conn->uhq);
> +	if (rc)
> +		goto nomem_uhq;
> +
> +	xhq_num_elements = uhq_num_elements;
> +	rc = qed_chain_alloc(p_hwfn->cdev,
> +			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> +			     QED_CHAIN_MODE_PBL,
> +			     QED_CHAIN_CNT_TYPE_U16,
> +			     xhq_num_elements,
> +			     sizeof(struct iscsi_xhqe), &p_conn->xhq);
> +	if (rc)
> +		goto nomem;
> +
> +	p_conn->free_on_delete = true;
> +	*p_out_conn = p_conn;
> +	return 0;
> +
> +nomem:
> +	qed_chain_free(p_hwfn->cdev, &p_conn->uhq);
> +nomem_uhq:
> +	qed_chain_free(p_hwfn->cdev, &p_conn->r2tq);
> +nomem_r2tq:
> +	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> +			  sizeof(struct tcp_upload_params),
> +			  p_conn->tcp_upload_params_virt_addr,
> +			  p_conn->tcp_upload_params_phys_addr);
> +nomem_upload_param:
> +	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> +			  sizeof(struct scsi_terminate_extra_params),
> +			  p_conn->queue_cnts_virt_addr,
> +			  p_conn->queue_cnts_phys_addr);
> +nomem_queue_cnts_param:
> +	kfree(p_conn);
> +
> +	return -ENOMEM;
> +}
> +
> +static int qed_iscsi_acquire_connection(struct qed_hwfn *p_hwfn,
> +					struct qed_iscsi_conn *p_in_conn,
> +					struct qed_iscsi_conn **p_out_conn)
> +{
> +	struct qed_iscsi_conn *p_conn = NULL;
> +	int rc = 0;
> +	u32 icid;
> +
> +	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> +	rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ISCSI, &icid);
> +	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +	if (rc)
> +		return rc;
> +
> +	/* Use input connection or allocate a new one */
> +	if (p_in_conn)
> +		p_conn = p_in_conn;
> +	else
> +		rc = qed_iscsi_allocate_connection(p_hwfn, &p_conn);
> +
> +	if (!rc)
> +		rc = qed_iscsi_setup_connection(p_hwfn, p_conn);
> +
> +	if (rc) {
> +		spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> +		qed_cxt_release_cid(p_hwfn, icid);
> +		spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +		return rc;
> +	}
> +
> +	p_conn->icid = icid;
> +	p_conn->conn_id = (u16)icid;
> +	p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid;
> +
> +	*p_out_conn = p_conn;
> +
> +	return rc;
> +}
> +
> +static void qed_iscsi_release_connection(struct qed_hwfn *p_hwfn,
> +					 struct qed_iscsi_conn *p_conn)
> +{
> +	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> +	list_add_tail(&p_conn->list_entry, &p_hwfn->p_iscsi_info->free_list);
> +	qed_cxt_release_cid(p_hwfn, p_conn->icid);
> +	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +}
> +
> +struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn)
> +{
> +	struct qed_iscsi_info *p_iscsi_info;
> +
> +	p_iscsi_info = kzalloc(sizeof(*p_iscsi_info), GFP_KERNEL);
> +	if (!p_iscsi_info) {
> +		DP_NOTICE(p_hwfn, "Failed to allocate qed_iscsi_info'\n");
> +		return NULL;
> +	}
> +
> +	INIT_LIST_HEAD(&p_iscsi_info->free_list);
> +	return p_iscsi_info;
> +}
> +
> +void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> +		     struct qed_iscsi_info *p_iscsi_info)
> +{
> +	spin_lock_init(&p_iscsi_info->lock);
> +}
> +
> +void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> +		    struct qed_iscsi_info *p_iscsi_info)
> +{
> +	kfree(p_iscsi_info);
> +}
> +
> +static void _qed_iscsi_get_tstats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct tstorm_iscsi_stats_drv tstats;
> +	u32 tstats_addr;
> +
> +	memset(&tstats, 0, sizeof(tstats));
> +	tstats_addr = BAR0_MAP_REG_TSDM_RAM +
> +		      TSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats));
> +
> +	p_stats->iscsi_rx_bytes_cnt =
> +	    HILO_64_REGPAIR(tstats.iscsi_rx_bytes_cnt);
> +	p_stats->iscsi_rx_packet_cnt =
> +	    HILO_64_REGPAIR(tstats.iscsi_rx_packet_cnt);
> +	p_stats->iscsi_cmdq_threshold_cnt =
> +	    le32_to_cpu(tstats.iscsi_cmdq_threshold_cnt);
> +	p_stats->iscsi_rq_threshold_cnt =
> +	    le32_to_cpu(tstats.iscsi_rq_threshold_cnt);
> +	p_stats->iscsi_immq_threshold_cnt =
> +	    le32_to_cpu(tstats.iscsi_immq_threshold_cnt);
> +}
> +
> +static void _qed_iscsi_get_mstats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct mstorm_iscsi_stats_drv mstats;
> +	u32 mstats_addr;
> +
> +	memset(&mstats, 0, sizeof(mstats));
> +	mstats_addr = BAR0_MAP_REG_MSDM_RAM +
> +		      MSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &mstats, mstats_addr, sizeof(mstats));
> +
> +	p_stats->iscsi_rx_dropped_pdus_task_not_valid =
> +	    HILO_64_REGPAIR(mstats.iscsi_rx_dropped_pdus_task_not_valid);
> +}
> +
> +static void _qed_iscsi_get_ustats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct ustorm_iscsi_stats_drv ustats;
> +	u32 ustats_addr;
> +
> +	memset(&ustats, 0, sizeof(ustats));
> +	ustats_addr = BAR0_MAP_REG_USDM_RAM +
> +		      USTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &ustats, ustats_addr, sizeof(ustats));
> +
> +	p_stats->iscsi_rx_data_pdu_cnt =
> +	    HILO_64_REGPAIR(ustats.iscsi_rx_data_pdu_cnt);
> +	p_stats->iscsi_rx_r2t_pdu_cnt =
> +	    HILO_64_REGPAIR(ustats.iscsi_rx_r2t_pdu_cnt);
> +	p_stats->iscsi_rx_total_pdu_cnt =
> +	    HILO_64_REGPAIR(ustats.iscsi_rx_total_pdu_cnt);
> +}
> +
> +static void _qed_iscsi_get_xstats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct xstorm_iscsi_stats_drv xstats;
> +	u32 xstats_addr;
> +
> +	memset(&xstats, 0, sizeof(xstats));
> +	xstats_addr = BAR0_MAP_REG_XSDM_RAM +
> +		      XSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &xstats, xstats_addr, sizeof(xstats));
> +
> +	p_stats->iscsi_tx_go_to_slow_start_event_cnt =
> +	    HILO_64_REGPAIR(xstats.iscsi_tx_go_to_slow_start_event_cnt);
> +	p_stats->iscsi_tx_fast_retransmit_event_cnt =
> +	    HILO_64_REGPAIR(xstats.iscsi_tx_fast_retransmit_event_cnt);
> +}
> +
> +static void _qed_iscsi_get_ystats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct ystorm_iscsi_stats_drv ystats;
> +	u32 ystats_addr;
> +
> +	memset(&ystats, 0, sizeof(ystats));
> +	ystats_addr = BAR0_MAP_REG_YSDM_RAM +
> +		      YSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &ystats, ystats_addr, sizeof(ystats));
> +
> +	p_stats->iscsi_tx_data_pdu_cnt =
> +	    HILO_64_REGPAIR(ystats.iscsi_tx_data_pdu_cnt);
> +	p_stats->iscsi_tx_r2t_pdu_cnt =
> +	    HILO_64_REGPAIR(ystats.iscsi_tx_r2t_pdu_cnt);
> +	p_stats->iscsi_tx_total_pdu_cnt =
> +	    HILO_64_REGPAIR(ystats.iscsi_tx_total_pdu_cnt);
> +}
> +
> +static void _qed_iscsi_get_pstats(struct qed_hwfn *p_hwfn,
> +				  struct qed_ptt *p_ptt,
> +				  struct qed_iscsi_stats *p_stats)
> +{
> +	struct pstorm_iscsi_stats_drv pstats;
> +	u32 pstats_addr;
> +
> +	memset(&pstats, 0, sizeof(pstats));
> +	pstats_addr = BAR0_MAP_REG_PSDM_RAM +
> +		      PSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> +	qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats));
> +
> +	p_stats->iscsi_tx_bytes_cnt =
> +	    HILO_64_REGPAIR(pstats.iscsi_tx_bytes_cnt);
> +	p_stats->iscsi_tx_packet_cnt =
> +	    HILO_64_REGPAIR(pstats.iscsi_tx_packet_cnt);
> +}
> +
> +static int qed_iscsi_get_stats(struct qed_hwfn *p_hwfn,
> +			       struct qed_iscsi_stats *stats)
> +{
> +	struct qed_ptt *p_ptt;
> +
> +	memset(stats, 0, sizeof(*stats));
> +
> +	p_ptt = qed_ptt_acquire(p_hwfn);
> +	if (!p_ptt) {
> +		DP_ERR(p_hwfn, "Failed to acquire ptt\n");
> +		return -EAGAIN;
> +	}
> +
> +	_qed_iscsi_get_tstats(p_hwfn, p_ptt, stats);
> +	_qed_iscsi_get_mstats(p_hwfn, p_ptt, stats);
> +	_qed_iscsi_get_ustats(p_hwfn, p_ptt, stats);
> +
> +	_qed_iscsi_get_xstats(p_hwfn, p_ptt, stats);
> +	_qed_iscsi_get_ystats(p_hwfn, p_ptt, stats);
> +	_qed_iscsi_get_pstats(p_hwfn, p_ptt, stats);
> +
> +	qed_ptt_release(p_hwfn, p_ptt);
> +
> +	return 0;
> +}
> +
> +struct qed_hash_iscsi_con {
> +	struct hlist_node node;
> +	struct qed_iscsi_conn *con;
> +};
> +
> +static int qed_fill_iscsi_dev_info(struct qed_dev *cdev,
> +				   struct qed_dev_iscsi_info *info)
> +{
> +	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
> +
> +	int rc;
> +
> +	memset(info, 0, sizeof(*info));
> +	rc = qed_fill_dev_info(cdev, &info->common);
> +
> +	info->primary_dbq_rq_addr =
> +	    qed_iscsi_get_primary_bdq_prod(hwfn, BDQ_ID_RQ);
> +	info->secondary_bdq_rq_addr =
> +	    qed_iscsi_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ);
> +
> +	return rc;
> +}
> +
> +static void qed_register_iscsi_ops(struct qed_dev *cdev,
> +				   struct qed_iscsi_cb_ops *ops, void *cookie)
> +{
> +	cdev->protocol_ops.iscsi = ops;
> +	cdev->ops_cookie = cookie;
> +}
> +
> +static struct qed_hash_iscsi_con *qed_iscsi_get_hash(struct qed_dev *cdev,
> +						     u32 handle)
> +{
> +	struct qed_hash_iscsi_con *hash_con = NULL;
> +
> +	if (!(cdev->flags & QED_FLAG_STORAGE_STARTED))
> +		return NULL;
> +
> +	hash_for_each_possible(cdev->connections, hash_con, node, handle) {
> +		if (hash_con->con->icid == handle)
> +			break;
> +	}
> +
> +	if (!hash_con || (hash_con->con->icid != handle))
> +		return NULL;
> +
> +	return hash_con;
> +}
> +
> +static int qed_iscsi_stop(struct qed_dev *cdev)
> +{
> +	int rc;
> +
> +	if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) {
> +		DP_NOTICE(cdev, "iscsi already stopped\n");
> +		return 0;
> +	}
> +
> +	if (!hash_empty(cdev->connections)) {
> +		DP_NOTICE(cdev,
> +			  "Can't stop iscsi - not all connections were returned\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Stop the iscsi */
> +	rc = qed_sp_iscsi_func_stop(QED_LEADING_HWFN(cdev),
> +				    QED_SPQ_MODE_EBLOCK, NULL);
> +	cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
> +
> +	return rc;
> +}
> +
> +static int qed_iscsi_start(struct qed_dev *cdev,
> +			   struct qed_iscsi_tid *tasks,
> +			   void *event_context,
> +			   iscsi_event_cb_t async_event_cb)
> +{
> +	int rc;
> +
> +	if (cdev->flags & QED_FLAG_STORAGE_STARTED) {
> +		DP_NOTICE(cdev, "iscsi already started;\n");
> +		return 0;
> +	}
> +
> +	rc = qed_sp_iscsi_func_start(QED_LEADING_HWFN(cdev),
> +				     QED_SPQ_MODE_EBLOCK, NULL, event_context,
> +				     async_event_cb);
> +	if (rc) {
> +		DP_NOTICE(cdev, "Failed to start iscsi\n");
> +		return rc;
> +	}
> +
> +	cdev->flags |= QED_FLAG_STORAGE_STARTED;
> +	hash_init(cdev->connections);
> +
> +	if (tasks) {
> +		struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
> +						       GFP_KERNEL);
> +
> +		if (!tid_info) {
> +			DP_NOTICE(cdev,
> +				  "Failed to allocate tasks information\n");
> +			qed_iscsi_stop(cdev);
> +			return -ENOMEM;
> +		}
> +
> +		rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
> +					      tid_info);
> +		if (rc) {
> +			DP_NOTICE(cdev, "Failed to gather task information\n");
> +			qed_iscsi_stop(cdev);
> +			kfree(tid_info);
> +			return rc;
> +		}
> +
> +		/* Fill task information */
> +		tasks->size = tid_info->tid_size;
> +		tasks->num_tids_per_block = tid_info->num_tids_per_block;
> +		memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
> +
> +		kfree(tid_info);
> +	}
> +
> +	return 0;
> +}
> +
> +static int qed_iscsi_acquire_conn(struct qed_dev *cdev,
> +				  u32 *handle,
> +				  u32 *fw_cid, void __iomem **p_doorbell)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +	int rc;
> +
> +	/* Allocate a hashed connection */
> +	hash_con = kzalloc(sizeof(*hash_con), GFP_ATOMIC);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to allocate hashed connection\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Acquire the connection */
> +	rc = qed_iscsi_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
> +					  &hash_con->con);
> +	if (rc) {
> +		DP_NOTICE(cdev, "Failed to acquire Connection\n");
> +		kfree(hash_con);
> +		return rc;
> +	}
> +
> +	/* Added the connection to hash table */
> +	*handle = hash_con->con->icid;
> +	*fw_cid = hash_con->con->fw_cid;
> +	hash_add(cdev->connections, &hash_con->node, *handle);
> +
> +	if (p_doorbell)
> +		*p_doorbell = qed_iscsi_get_db_addr(QED_LEADING_HWFN(cdev),
> +						    *handle);
> +
> +	return 0;
> +}
> +
> +static int qed_iscsi_release_conn(struct qed_dev *cdev, u32 handle)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +
> +	hash_con = qed_iscsi_get_hash(cdev, handle);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> +			  handle);
> +		return -EINVAL;
> +	}
> +
> +	hlist_del(&hash_con->node);
> +	qed_iscsi_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
> +	kfree(hash_con);
> +
> +	return 0;
> +}
> +
> +static int qed_iscsi_offload_conn(struct qed_dev *cdev,
> +				  u32 handle,
> +				  struct qed_iscsi_params_offload *conn_info)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +	struct qed_iscsi_conn *con;
> +
> +	hash_con = qed_iscsi_get_hash(cdev, handle);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> +			  handle);
> +		return -EINVAL;
> +	}
> +
> +	/* Update the connection with information from the params */
> +	con = hash_con->con;
> +
> +	ether_addr_copy(con->local_mac, conn_info->src.mac);
> +	ether_addr_copy(con->remote_mac, conn_info->dst.mac);
> +	memcpy(con->local_ip, conn_info->src.ip, sizeof(con->local_ip));
> +	memcpy(con->remote_ip, conn_info->dst.ip, sizeof(con->remote_ip));
> +	con->local_port = conn_info->src.port;
> +	con->remote_port = conn_info->dst.port;
> +
> +	con->layer_code = conn_info->layer_code;
> +	con->sq_pbl_addr = conn_info->sq_pbl_addr;
> +	con->initial_ack = conn_info->initial_ack;
> +	con->vlan_id = conn_info->vlan_id;
> +	con->tcp_flags = conn_info->tcp_flags;
> +	con->ip_version = conn_info->ip_version;
> +	con->default_cq = conn_info->default_cq;
> +	con->ka_max_probe_cnt = conn_info->ka_max_probe_cnt;
> +	con->dup_ack_theshold = conn_info->dup_ack_theshold;
> +	con->rcv_next = conn_info->rcv_next;
> +	con->snd_una = conn_info->snd_una;
> +	con->snd_next = conn_info->snd_next;
> +	con->snd_max = conn_info->snd_max;
> +	con->snd_wnd = conn_info->snd_wnd;
> +	con->rcv_wnd = conn_info->rcv_wnd;
> +	con->snd_wl1 = conn_info->snd_wl1;
> +	con->cwnd = conn_info->cwnd;
> +	con->ss_thresh = conn_info->ss_thresh;
> +	con->srtt = conn_info->srtt;
> +	con->rtt_var = conn_info->rtt_var;
> +	con->ts_time = conn_info->ts_time;
> +	con->ts_recent = conn_info->ts_recent;
> +	con->ts_recent_age = conn_info->ts_recent_age;
> +	con->total_rt = conn_info->total_rt;
> +	con->ka_timeout_delta = conn_info->ka_timeout_delta;
> +	con->rt_timeout_delta = conn_info->rt_timeout_delta;
> +	con->dup_ack_cnt = conn_info->dup_ack_cnt;
> +	con->snd_wnd_probe_cnt = conn_info->snd_wnd_probe_cnt;
> +	con->ka_probe_cnt = conn_info->ka_probe_cnt;
> +	con->rt_cnt = conn_info->rt_cnt;
> +	con->flow_label = conn_info->flow_label;
> +	con->ka_timeout = conn_info->ka_timeout;
> +	con->ka_interval = conn_info->ka_interval;
> +	con->max_rt_time = conn_info->max_rt_time;
> +	con->initial_rcv_wnd = conn_info->initial_rcv_wnd;
> +	con->ttl = conn_info->ttl;
> +	con->tos_or_tc = conn_info->tos_or_tc;
> +	con->remote_port = conn_info->remote_port;
> +	con->local_port = conn_info->local_port;
> +	con->mss = conn_info->mss;
> +	con->snd_wnd_scale = conn_info->snd_wnd_scale;
> +	con->rcv_wnd_scale = conn_info->rcv_wnd_scale;
> +	con->ts_ticks_per_second = conn_info->ts_ticks_per_second;
> +	con->da_timeout_value = conn_info->da_timeout_value;
> +	con->ack_frequency = conn_info->ack_frequency;
> +
> +	/* Set default values on other connection fields */
> +	con->offl_flags = 0x1;
> +
> +	return qed_sp_iscsi_conn_offload(QED_LEADING_HWFN(cdev), con,
> +					 QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_update_conn(struct qed_dev *cdev,
> +				 u32 handle,
> +				 struct qed_iscsi_params_update *conn_info)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +	struct qed_iscsi_conn *con;
> +
> +	hash_con = qed_iscsi_get_hash(cdev, handle);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> +			  handle);
> +		return -EINVAL;
> +	}
> +
> +	/* Update the connection with information from the params */
> +	con = hash_con->con;
> +	con->update_flag = conn_info->update_flag;
> +	con->max_seq_size = conn_info->max_seq_size;
> +	con->max_recv_pdu_length = conn_info->max_recv_pdu_length;
> +	con->max_send_pdu_length = conn_info->max_send_pdu_length;
> +	con->first_seq_length = conn_info->first_seq_length;
> +	con->exp_stat_sn = conn_info->exp_stat_sn;
> +
> +	return qed_sp_iscsi_conn_update(QED_LEADING_HWFN(cdev), con,
> +					QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_clear_conn_sq(struct qed_dev *cdev, u32 handle)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +
> +	hash_con = qed_iscsi_get_hash(cdev, handle);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> +			  handle);
> +		return -EINVAL;
> +	}
> +
> +	return qed_sp_iscsi_conn_clear_sq(QED_LEADING_HWFN(cdev),
> +					  hash_con->con,
> +					  QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_destroy_conn(struct qed_dev *cdev,
> +				  u32 handle, u8 abrt_conn)
> +{
> +	struct qed_hash_iscsi_con *hash_con;
> +
> +	hash_con = qed_iscsi_get_hash(cdev, handle);
> +	if (!hash_con) {
> +		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> +			  handle);
> +		return -EINVAL;
> +	}
> +
> +	hash_con->con->abortive_dsconnect = abrt_conn;
> +
> +	return qed_sp_iscsi_conn_terminate(QED_LEADING_HWFN(cdev),
> +					   hash_con->con,
> +					   QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats)
> +{
> +	return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats);
> +}
> +
> +static const struct qed_iscsi_ops qed_iscsi_ops_pass = {
> +	.common = &qed_common_ops_pass,
> +	.ll2 = &qed_ll2_ops_pass,
> +	.fill_dev_info = &qed_fill_iscsi_dev_info,
> +	.register_ops = &qed_register_iscsi_ops,
> +	.start = &qed_iscsi_start,
> +	.stop = &qed_iscsi_stop,
> +	.acquire_conn = &qed_iscsi_acquire_conn,
> +	.release_conn = &qed_iscsi_release_conn,
> +	.offload_conn = &qed_iscsi_offload_conn,
> +	.update_conn = &qed_iscsi_update_conn,
> +	.destroy_conn = &qed_iscsi_destroy_conn,
> +	.clear_sq = &qed_iscsi_clear_conn_sq,
> +	.get_stats = &qed_iscsi_stats,
> +};
> +
> +const struct qed_iscsi_ops *qed_get_iscsi_ops()
> +{
> +	return &qed_iscsi_ops_pass;
> +}
> +EXPORT_SYMBOL(qed_get_iscsi_ops);
> +
> +void qed_put_iscsi_ops(void)
> +{
> +}
> +EXPORT_SYMBOL(qed_put_iscsi_ops);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> new file mode 100644
> index 0000000..269848c
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> @@ -0,0 +1,52 @@
> +/* QLogic qed NIC Driver
> + * Copyright (c) 2015 QLogic Corporation
> + *
> + * This software is available 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.
> + */
> +
> +#ifndef _QED_ISCSI_H
> +#define _QED_ISCSI_H
> +#include <linux/types.h>
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/qed/tcp_common.h>
> +#include <linux/qed/qed_iscsi_if.h>
> +#include <linux/qed/qed_chain.h>
> +#include "qed.h"
> +#include "qed_hsi.h"
> +#include "qed_mcp.h"
> +#include "qed_sp.h"
> +
> +struct qed_iscsi_info {
> +	spinlock_t lock;
> +	struct list_head free_list;
> +	u16 max_num_outstanding_tasks;
> +	void *event_context;
> +	iscsi_event_cb_t event_cb;
> +};
> +
> +#ifdef CONFIG_QED_LL2
> +extern const struct qed_ll2_ops qed_ll2_ops_pass;
> +#endif
> +
> +#if IS_ENABLED(CONFIG_QEDI)
> +struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn);
> +
> +void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> +		     struct qed_iscsi_info *p_iscsi_info);
> +
> +void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> +		    struct qed_iscsi_info *p_iscsi_info);
> +#else /* IS_ENABLED(CONFIG_QEDI) */
> +static inline struct qed_iscsi_info *qed_iscsi_alloc(
> +		struct qed_hwfn *p_hwfn) { return NULL; }
> +static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> +		struct qed_iscsi_info *p_iscsi_info) {}
> +static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> +		struct qed_iscsi_info *p_iscsi_info) {}
> +#endif /* IS_ENABLED(CONFIG_QEDI) */
> +
> +#endif
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> index ddd410a..07e2f77 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> @@ -2187,6 +2187,5 @@ const struct qed_eth_ops *qed_get_eth_ops(void)
>  
>  void qed_put_eth_ops(void)
>  {
> -	/* TODO - reference count for module? */
>  }
>  EXPORT_SYMBOL(qed_put_eth_ops);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> index a6db107..e67f3c9 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> @@ -299,6 +299,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
>  		p_tx->cur_completing_bd_idx = 1;
>  		b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
>  		tx_frag = p_pkt->bds_set[0].tx_frag;
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
>  		if (p_ll2_conn->gsi_enable)
>  			qed_ll2b_release_tx_gsi_packet(p_hwfn,
>  						       p_ll2_conn->my_id,
> @@ -307,6 +308,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
>  						       b_last_frag,
>  						       b_last_packet);
>  		else
> +#endif
>  			qed_ll2b_complete_tx_packet(p_hwfn,
>  						    p_ll2_conn->my_id,
>  						    p_pkt->cookie,
Huh? What is that doing here?

> @@ -367,6 +369,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
>  
>  		spin_unlock_irqrestore(&p_tx->lock, flags);
>  		tx_frag = p_pkt->bds_set[0].tx_frag;
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
>  		if (p_ll2_conn->gsi_enable)
>  			qed_ll2b_complete_tx_gsi_packet(p_hwfn,
>  							p_ll2_conn->my_id,
> @@ -374,6 +377,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
>  							tx_frag,
>  							b_last_frag, !num_bds);
>  		else
> +#endif
>  			qed_ll2b_complete_tx_packet(p_hwfn,
>  						    p_ll2_conn->my_id,
>  						    p_pkt->cookie,
> @@ -421,6 +425,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
>  			  "Mismatch between active_descq and the LL2 Rx chain\n");
>  	list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
>  
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
>  	spin_unlock_irqrestore(&p_rx->lock, lock_flags);
>  	qed_ll2b_complete_rx_gsi_packet(p_hwfn,
>  					p_ll2_info->my_id,
> @@ -433,6 +438,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
>  					src_mac_addrhi,
>  					src_mac_addrlo, b_last_cqe);
>  	spin_lock_irqsave(&p_rx->lock, lock_flags);
> +#endif
>  
>  	return 0;
>  }
> @@ -1516,11 +1522,12 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev,
>  
>  static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
>  {
> -	struct qed_ll2_info ll2_info;
> +	struct qed_ll2_info *ll2_info;
>  	struct qed_ll2_buffer *buffer;
>  	enum qed_ll2_conn_type conn_type;
>  	struct qed_ptt *p_ptt;
>  	int rc, i;
> +	u8 gsi_enable = 1;
>  
>  	/* Initialize LL2 locks & lists */
>  	INIT_LIST_HEAD(&cdev->ll2->list);
> @@ -1552,6 +1559,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
>  	switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
>  	case QED_PCI_ISCSI:
>  		conn_type = QED_LL2_TYPE_ISCSI;
> +		gsi_enable = 0;
>  		break;
>  	case QED_PCI_ETH_ROCE:
>  		conn_type = QED_LL2_TYPE_ROCE;
> @@ -1561,18 +1569,23 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
>  	}
>  
>  	/* Prepare the temporary ll2 information */
> -	memset(&ll2_info, 0, sizeof(ll2_info));
> -	ll2_info.conn_type = conn_type;
> -	ll2_info.mtu = params->mtu;
> -	ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
> -	ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
> -	ll2_info.tx_tc = 0;
> -	ll2_info.tx_dest = CORE_TX_DEST_NW;
> -	ll2_info.gsi_enable = 1;
> -
> -	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
> +	ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
> +	if (!ll2_info) {
> +		DP_INFO(cdev, "Failed to allocate LL2 info buffer\n");
> +		goto fail;
> +	}
> +	ll2_info->conn_type = conn_type;
> +	ll2_info->mtu = params->mtu;
> +	ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
> +	ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
> +	ll2_info->tx_tc = 0;
> +	ll2_info->tx_dest = CORE_TX_DEST_NW;
> +	ll2_info->gsi_enable = gsi_enable;
> +
> +	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), ll2_info,
>  					QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
>  					&cdev->ll2->handle);
> +	kfree(ll2_info);
>  	if (rc) {
>  		DP_INFO(cdev, "Failed to acquire LL2 connection\n");
>  		goto fail;
Where is the benefit of this hunk? And is it related to iSCSI?

> diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
> index 4ee3151..a01ad9d 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_main.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
> @@ -1239,7 +1239,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
>  	if (link.link_up)
>  		if_link->link_up = true;
>  
> -	/* TODO - at the moment assume supported and advertised speed equal */
>  	if_link->supported_caps = QED_LM_FIBRE_BIT;
>  	if (params.speed.autoneg)
>  		if_link->supported_caps |= QED_LM_Autoneg_BIT;
> @@ -1294,7 +1293,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
>  	if (link.link_up)
>  		if_link->speed = link.speed;
>  
> -	/* TODO - fill duplex properly */
>  	if_link->duplex = DUPLEX_FULL;
>  	qed_mcp_get_media_type(hwfn->cdev, &media_type);
>  	if_link->port = qed_get_port_type(media_type);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> index dff520e..2e5f51b 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> @@ -314,9 +314,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
>  
>  /* Using hwfn number (and not pf_num) is required since in CMT mode,
>   * same pf_num may be used by two different hwfn
> - * TODO - this shouldn't really be in .h file, but until all fields
> - * required during hw-init will be placed in their correct place in shmem
> - * we need it in qed_dev.c [for readin the nvram reflection in shmem].
>   */
>  #define MCP_PF_ID_BY_REL(p_hwfn, rel_pfid) (QED_IS_BB((p_hwfn)->cdev) ?	       \
>  					    ((rel_pfid) |		       \
> @@ -324,9 +321,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
>  					    rel_pfid)
>  #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id)
>  
> -/* TODO - this is only correct as long as only BB is supported, and
> - * no port-swapping is implemented; Afterwards we'll need to fix it.
> - */
>  #define MFW_PORT(_p_hwfn)       ((_p_hwfn)->abs_pf_id %	\
>  				 ((_p_hwfn)->cdev->num_ports_in_engines * 2))
>  struct qed_mcp_info {
Please split off the patch and use a separate one to remove all the TODO
entries. They do not relate to the iSCSI offload bit.

> diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> index b414a05..9754420 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> @@ -82,6 +82,8 @@
>  	0x1c80000UL
>  #define BAR0_MAP_REG_XSDM_RAM \
>  	0x1e00000UL
> +#define BAR0_MAP_REG_YSDM_RAM \
> +	0x1e80000UL
>  #define  NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
>  	0x5011f4UL
>  #define  PRS_REG_SEARCH_TCP \
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> index caff415..d3fa578 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> @@ -24,6 +24,7 @@
>  #include "qed_hsi.h"
>  #include "qed_hw.h"
>  #include "qed_int.h"
> +#include "qed_iscsi.h"
>  #include "qed_mcp.h"
>  #include "qed_reg_addr.h"
>  #include "qed_sp.h"
> @@ -249,6 +250,20 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
>  		return qed_sriov_eqe_event(p_hwfn,
>  					   p_eqe->opcode,
>  					   p_eqe->echo, &p_eqe->data);
> +	case PROTOCOLID_ISCSI:
> +		if (!IS_ENABLED(CONFIG_QEDI))
> +			return -EINVAL;
> +
> +		if (p_hwfn->p_iscsi_info->event_cb) {
> +			struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info;
> +
> +			return p_iscsi->event_cb(p_iscsi->event_context,
> +						 p_eqe->opcode, &p_eqe->data);
> +		} else {
> +			DP_NOTICE(p_hwfn,
> +				  "iSCSI async completion is not set\n");
> +			return -EINVAL;
> +		}
>  	default:
>  		DP_NOTICE(p_hwfn,
>  			  "Unknown Async completion for protocol: %d\n",
> diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
> index f9ae903..c0c9fa8 100644
> --- a/include/linux/qed/qed_if.h
> +++ b/include/linux/qed/qed_if.h
> @@ -165,6 +165,7 @@ struct qed_iscsi_pf_params {
>  	u32 max_cwnd;
>  	u16 cq_num_entries;
>  	u16 cmdq_num_entries;
> +	u32 two_msl_timer;
>  	u16 dup_ack_threshold;
>  	u16 tx_sws_timer;
>  	u16 min_rto;
> @@ -271,6 +272,7 @@ struct qed_dev_info {
>  enum qed_sb_type {
>  	QED_SB_TYPE_L2_QUEUE,
>  	QED_SB_TYPE_CNQ,
> +	QED_SB_TYPE_STORAGE,
>  };
>  
>  enum qed_protocol {
> diff --git a/include/linux/qed/qed_iscsi_if.h b/include/linux/qed/qed_iscsi_if.h
> new file mode 100644
> index 0000000..6735ee5
> --- /dev/null
> +++ b/include/linux/qed/qed_iscsi_if.h
> @@ -0,0 +1,249 @@
> +/* QLogic qed NIC Driver
Again, this is the iSCSI driver, is it not?

> + * Copyright (c) 2015 QLogic Corporation
> + *
And you _might_ want to check the copyright, seeing that it's being
posted from the cavium.com domain ...

Cheers,

Hannes
Johannes Thumshirn Oct. 19, 2016, 9:09 a.m. UTC | #2
Hi Manish,

Some initital comments

On Wed, Oct 19, 2016 at 01:01:08AM -0400, manish.rangankar@cavium.com wrote:
> From: Yuval Mintz <Yuval.Mintz@qlogic.com>
> 
> This adds the backbone required for the various HW initalizations
> which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
> 4xxxx line of adapters - FW notification, resource initializations, etc.
> 
> Signed-off-by: Arun Easi <arun.easi@cavium.com>
> Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
> ---
>  drivers/net/ethernet/qlogic/Kconfig            |   15 +
>  drivers/net/ethernet/qlogic/qed/Makefile       |    1 +
>  drivers/net/ethernet/qlogic/qed/qed.h          |    8 +-
>  drivers/net/ethernet/qlogic/qed/qed_dev.c      |   15 +
>  drivers/net/ethernet/qlogic/qed/qed_int.h      |    1 -
>  drivers/net/ethernet/qlogic/qed/qed_iscsi.c    | 1310 ++++++++++++++++++++++++
>  drivers/net/ethernet/qlogic/qed/qed_iscsi.h    |   52 +
>  drivers/net/ethernet/qlogic/qed/qed_l2.c       |    1 -
>  drivers/net/ethernet/qlogic/qed/qed_ll2.c      |   35 +-
>  drivers/net/ethernet/qlogic/qed/qed_main.c     |    2 -
>  drivers/net/ethernet/qlogic/qed/qed_mcp.h      |    6 -
>  drivers/net/ethernet/qlogic/qed/qed_reg_addr.h |    2 +
>  drivers/net/ethernet/qlogic/qed/qed_spq.c      |   15 +
>  include/linux/qed/qed_if.h                     |    2 +
>  include/linux/qed/qed_iscsi_if.h               |  249 +++++
>  15 files changed, 1692 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
>  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
>  create mode 100644 include/linux/qed/qed_iscsi_if.h
> 
> diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
> index 0df1391f9..bad4fae 100644
> --- a/drivers/net/ethernet/qlogic/Kconfig
> +++ b/drivers/net/ethernet/qlogic/Kconfig
> @@ -118,4 +118,19 @@ config INFINIBAND_QEDR
>  	  for QLogic QED. This would be replaced by the 'real' option
>  	  once the QEDR driver is added [+relocated].
>  
> +config QED_ISCSI
> +	bool
> +
> +config QEDI
> +	tristate "QLogic QED 25/40/100Gb iSCSI driver"
> +	depends on QED
> +	select QED_LL2
> +	select QED_ISCSI
> +	default n
> +	---help---
> +	  This provides a temporary node that allows the compilation
> +	  and logical testing of the hardware offload iSCSI support
> +	  for QLogic QED. This would be replaced by the 'real' option
> +	  once the QEDI driver is added [+relocated].
> +
>  endif # NET_VENDOR_QLOGIC
> diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
> index cda0af7..b76669c 100644
> --- a/drivers/net/ethernet/qlogic/qed/Makefile
> +++ b/drivers/net/ethernet/qlogic/qed/Makefile
> @@ -6,3 +6,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
>  qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
>  qed-$(CONFIG_QED_LL2) += qed_ll2.o
>  qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
> +qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
> diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
> index 653bb57..a61b1c0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed.h
> @@ -35,6 +35,7 @@
>  
>  #define QED_WFQ_UNIT	100
>  
> +#define ISCSI_BDQ_ID(_port_id) (_port_id)

This looks a bit odd to me.

[...]

>  #endif
> +		if (IS_ENABLED(CONFIG_QEDI) &&
> +				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> +			qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);


Why not introduce a small helper like:
static inline bool qed_is_iscsi_personality()
{
	return IS_ENABLED(CONFIG_QEDI) && p_hwfn->hw_info.personality ==
		QED_PCI_ISCSI;
}

>  		qed_iov_free(p_hwfn);

[...]

> +
> +	if (!GET_FIELD(p_ramrod->iscsi.flags,
> +		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> +		p_tcp = &p_ramrod->tcp;
> +		ucval = p_conn->local_mac[1];
> +		((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->local_mac[0];
> +		((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->local_mac[3];
> +		((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->local_mac[2];
> +		((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->local_mac[5];
> +		((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->local_mac[4];
> +		((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
> +		ucval = p_conn->remote_mac[1];
> +		((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->remote_mac[0];
> +		((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->remote_mac[3];
> +		((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->remote_mac[2];
> +		((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->remote_mac[5];
> +		((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->remote_mac[4];
> +		((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
> +
> +		p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
> +
> +		p_tcp->flags = p_conn->tcp_flags;
> +		p_tcp->ip_version = p_conn->ip_version;
> +		for (i = 0; i < 4; i++) {
> +			dval = p_conn->remote_ip[i];
> +			p_tcp->remote_ip[i] = cpu_to_le32(dval);
> +			dval = p_conn->local_ip[i];
> +			p_tcp->local_ip[i] = cpu_to_le32(dval);
> +		}
> +		p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
> +		p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
> +
> +		p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
> +		p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
> +		p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
> +		p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
> +		p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
> +		p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
> +		p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
> +		p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
> +		p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
> +		p_tcp->srtt = cpu_to_le16(p_conn->srtt);
> +		p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
> +		p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
> +		p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
> +		p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
> +		p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
> +		dval = p_conn->ka_timeout_delta;
> +		p_tcp->ka_timeout_delta = cpu_to_le32(dval);
> +		dval = p_conn->rt_timeout_delta;
> +		p_tcp->rt_timeout_delta = cpu_to_le32(dval);
> +		p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
> +		p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
> +		p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
> +		p_tcp->rt_cnt = p_conn->rt_cnt;
> +		p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
> +		p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
> +		p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
> +		p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
> +		dval = p_conn->initial_rcv_wnd;
> +		p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
> +		p_tcp->ttl = p_conn->ttl;
> +		p_tcp->tos_or_tc = p_conn->tos_or_tc;
> +		p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
> +		p_tcp->local_port = cpu_to_le16(p_conn->local_port);
> +		p_tcp->mss = cpu_to_le16(p_conn->mss);
> +		p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
> +		p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> +		dval = p_conn->ts_ticks_per_second;
> +		p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
> +		wval = p_conn->da_timeout_value;
> +		p_tcp->da_timeout_value = cpu_to_le16(wval);
> +		p_tcp->ack_frequency = p_conn->ack_frequency;
> +		p_tcp->connect_mode = p_conn->connect_mode;
> +	} else {
> +		p_tcp2 =
> +		    &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
> +		ucval = p_conn->local_mac[1];
> +		((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->local_mac[0];
> +		((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->local_mac[3];
> +		((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->local_mac[2];
> +		((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->local_mac[5];
> +		((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->local_mac[4];
> +		((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
> +
> +		ucval = p_conn->remote_mac[1];
> +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
> +		ucval = p_conn->remote_mac[0];
> +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
> +		ucval = p_conn->remote_mac[3];
> +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
> +		ucval = p_conn->remote_mac[2];
> +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
> +		ucval = p_conn->remote_mac[5];
> +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
> +		ucval = p_conn->remote_mac[4];
> +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
> +
> +		p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);
> +		p_tcp2->flags = p_conn->tcp_flags;
> +
> +		p_tcp2->ip_version = p_conn->ip_version;
> +		for (i = 0; i < 4; i++) {
> +			dval = p_conn->remote_ip[i];
> +			p_tcp2->remote_ip[i] = cpu_to_le32(dval);
> +			dval = p_conn->local_ip[i];
> +			p_tcp2->local_ip[i] = cpu_to_le32(dval);
> +		}
> +
> +		p_tcp2->flow_label = cpu_to_le32(p_conn->flow_label);
> +		p_tcp2->ttl = p_conn->ttl;
> +		p_tcp2->tos_or_tc = p_conn->tos_or_tc;
> +		p_tcp2->remote_port = cpu_to_le16(p_conn->remote_port);
> +		p_tcp2->local_port = cpu_to_le16(p_conn->local_port);
> +		p_tcp2->mss = cpu_to_le16(p_conn->mss);
> +		p_tcp2->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> +		p_tcp2->connect_mode = p_conn->connect_mode;
> +		wval = p_conn->syn_ip_payload_length;
> +		p_tcp2->syn_ip_payload_length = cpu_to_le16(wval);
> +		p_tcp2->syn_phy_addr_lo = DMA_LO_LE(p_conn->syn_phy_addr);
> +		p_tcp2->syn_phy_addr_hi = DMA_HI_LE(p_conn->syn_phy_addr);
> +	}

Is there any chance you could factor out above blocks into own functions so
you have


	if (!GET_FIELD(p_ramrod->iscsi.flags,
		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
		qedi_do_stuff_off_chip();
	else 
		qedi_do_stuff_on_chip();

> +

[...]

> +static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
> +{
> +	return (u8 __iomem *)p_hwfn->doorbells +
> +			     qed_db_addr(cid, DQ_DEMS_LEGACY);
> +}
> +
> +static void __iomem *qed_iscsi_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
> +						    u8 bdq_id)
> +{
> +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
> +			     MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> +							     bdq_id);
> +}
> +
> +static void __iomem *qed_iscsi_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
> +						      u8 bdq_id)
> +{
> +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
> +			     TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> +							     bdq_id);
> +}

Why are you casting to u8* here, you're returning void*? 

[...]

> +
> +	if (tasks) {
> +		struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
> +						       GFP_KERNEL);
> +
> +		if (!tid_info) {
> +			DP_NOTICE(cdev,
> +				  "Failed to allocate tasks information\n");
> +			qed_iscsi_stop(cdev);
> +			return -ENOMEM;
> +		}
> +
> +		rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
> +					      tid_info);
> +		if (rc) {
> +			DP_NOTICE(cdev, "Failed to gather task information\n");
> +			qed_iscsi_stop(cdev);
> +			kfree(tid_info);
> +			return rc;
> +		}
> +
> +		/* Fill task information */
> +		tasks->size = tid_info->tid_size;
> +		tasks->num_tids_per_block = tid_info->num_tids_per_block;
> +		memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
> +
> +		kfree(tid_info);
> +	}
> +
> +	return 0;
> +}

Maybe:

struct qed_tid_mem *tid_info;
[...]
if (!tasks)
	return 0;

tid_info = kzalloc(sizeof(*tid_info), GFP_KERNEL);

if (!tid_info) {
	DP_NOTICE(cdev, "Failed to allocate tasks information\n");
	qed_iscsi_stop(cdev);
	return -ENOMEM;
}

rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev), tid_info);
if (rc) {
	DP_NOTICE(cdev, "Failed to gather task information\n");
	qed_iscsi_stop(cdev);
	kfree(tid_info);
	return rc;
}

/* Fill task information */
tasks->size = tid_info->tid_size;
tasks->num_tids_per_block = tid_info->num_tids_per_block;
memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);

kfree(tid_info);

> +

[...]

> +/**
> + * @brief start iscsi in FW
> + *
> + * @param cdev
> + * @param tasks - qed will fill information about tasks
> + *

Please use proper kerneldoc and not doxygen syntax.

Thanks,
	Johannes
Arun Easi Oct. 19, 2016, 10:28 p.m. UTC | #3
Thanks Hannes for the review. Please see my comments inline..

On Wed, 19 Oct 2016, 12:31am, Hannes Reinecke wrote:

> On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> > From: Yuval Mintz <Yuval.Mintz@qlogic.com>
> > 
> > This adds the backbone required for the various HW initalizations
> > which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
> > 4xxxx line of adapters - FW notification, resource initializations, etc.
> > 
> > Signed-off-by: Arun Easi <arun.easi@cavium.com>
> > Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
> > ---
> >  drivers/net/ethernet/qlogic/Kconfig            |   15 +
> >  drivers/net/ethernet/qlogic/qed/Makefile       |    1 +
> >  drivers/net/ethernet/qlogic/qed/qed.h          |    8 +-
> >  drivers/net/ethernet/qlogic/qed/qed_dev.c      |   15 +
> >  drivers/net/ethernet/qlogic/qed/qed_int.h      |    1 -
> >  drivers/net/ethernet/qlogic/qed/qed_iscsi.c    | 1310 ++++++++++++++++++++++++
> >  drivers/net/ethernet/qlogic/qed/qed_iscsi.h    |   52 +
> >  drivers/net/ethernet/qlogic/qed/qed_l2.c       |    1 -
> >  drivers/net/ethernet/qlogic/qed/qed_ll2.c      |   35 +-
> >  drivers/net/ethernet/qlogic/qed/qed_main.c     |    2 -
> >  drivers/net/ethernet/qlogic/qed/qed_mcp.h      |    6 -
> >  drivers/net/ethernet/qlogic/qed/qed_reg_addr.h |    2 +
> >  drivers/net/ethernet/qlogic/qed/qed_spq.c      |   15 +
> >  include/linux/qed/qed_if.h                     |    2 +
> >  include/linux/qed/qed_iscsi_if.h               |  249 +++++
> >  15 files changed, 1692 insertions(+), 22 deletions(-)
> >  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> >  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> >  create mode 100644 include/linux/qed/qed_iscsi_if.h
> > 

-- snipped --

> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> > new file mode 100644
> > index 0000000..cb22dad
> > --- /dev/null
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> > @@ -0,0 +1,1310 @@
> > +/* QLogic qed NIC Driver
> 
> Shouldn't that be qedi iSCSI Driver?

Actually, this is the common module under drivers/net/, which was 
submitted along with the NIC driver, qede, so the comment stayed.

In this driver architecture, for all protocols, there is this
common module, qed, as well as a protocol module (qede, qedr, qedi
etc.).

This comment needs to be changed in all files under qed/. We will submit 
another patch to do that.

> > +static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn,
> > +				     struct qed_iscsi_conn *p_conn,
> > +				     enum spq_mode comp_mode,
> > +				     struct qed_spq_comp_cb *p_comp_addr)
> > +{
> > +	struct iscsi_spe_conn_offload *p_ramrod = NULL;
> > +	struct tcp_offload_params_opt2 *p_tcp2 = NULL;
> > +	struct tcp_offload_params *p_tcp = NULL;
> > +	struct qed_spq_entry *p_ent = NULL;
> > +	struct qed_sp_init_data init_data;
> > +	union qed_qm_pq_params pq_params;
> > +	u16 pq0_id = 0, pq1_id = 0;
> > +	dma_addr_t r2tq_pbl_addr;
> > +	dma_addr_t xhq_pbl_addr;
> > +	dma_addr_t uhq_pbl_addr;
> > +	int rc = 0;
> > +	u32 dval;
> > +	u16 wval;
> > +	u8 ucval;
> > +	u8 i;
> > +
> > +	/* Get SPQ entry */
> > +	memset(&init_data, 0, sizeof(init_data));
> > +	init_data.cid = p_conn->icid;
> > +	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> > +	init_data.comp_mode = comp_mode;
> > +	init_data.p_comp_data = p_comp_addr;
> > +
> > +	rc = qed_sp_init_request(p_hwfn, &p_ent,
> > +				 ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN,
> > +				 PROTOCOLID_ISCSI, &init_data);
> > +	if (rc)
> > +		return rc;
> > +
> > +	p_ramrod = &p_ent->ramrod.iscsi_conn_offload;
> > +
> > +	/* Transmission PQ is the first of the PF */
> > +	memset(&pq_params, 0, sizeof(pq_params));
> > +	pq0_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> > +	p_conn->physical_q0 = cpu_to_le16(pq0_id);
> > +	p_ramrod->iscsi.physical_q0 = cpu_to_le16(pq0_id);
> > +
> > +	/* iSCSI Pure-ACK PQ */
> > +	pq_params.iscsi.q_idx = 1;
> > +	pq1_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> > +	p_conn->physical_q1 = cpu_to_le16(pq1_id);
> > +	p_ramrod->iscsi.physical_q1 = cpu_to_le16(pq1_id);
> > +
> > +	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN;
> > +	SET_FIELD(p_ramrod->hdr.flags, ISCSI_SLOW_PATH_HDR_LAYER_CODE,
> > +		  p_conn->layer_code);
> > +
> > +	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> > +	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> > +
> > +	DMA_REGPAIR_LE(p_ramrod->iscsi.sq_pbl_addr, p_conn->sq_pbl_addr);
> > +
> > +	r2tq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->r2tq);
> > +	DMA_REGPAIR_LE(p_ramrod->iscsi.r2tq_pbl_addr, r2tq_pbl_addr);
> > +
> > +	xhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->xhq);
> > +	DMA_REGPAIR_LE(p_ramrod->iscsi.xhq_pbl_addr, xhq_pbl_addr);
> > +
> > +	uhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->uhq);
> > +	DMA_REGPAIR_LE(p_ramrod->iscsi.uhq_pbl_addr, uhq_pbl_addr);
> > +
> > +	p_ramrod->iscsi.initial_ack = cpu_to_le32(p_conn->initial_ack);
> > +	p_ramrod->iscsi.flags = p_conn->offl_flags;
> > +	p_ramrod->iscsi.default_cq = p_conn->default_cq;
> > +	p_ramrod->iscsi.stat_sn = cpu_to_le32(p_conn->stat_sn);
> > +
> > +	if (!GET_FIELD(p_ramrod->iscsi.flags,
> > +		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> > +		p_tcp = &p_ramrod->tcp;
> > +		ucval = p_conn->local_mac[1];
> > +		((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->local_mac[0];
> > +		((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->local_mac[3];
> > +		((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->local_mac[2];
> > +		((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->local_mac[5];
> > +		((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->local_mac[4];
> > +		((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
> > +		ucval = p_conn->remote_mac[1];
> > +		((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->remote_mac[0];
> > +		((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->remote_mac[3];
> > +		((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->remote_mac[2];
> > +		((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->remote_mac[5];
> > +		((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->remote_mac[4];
> > +		((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
> > +
> This looks terribly like endianness swapping. You sure this is
> applicable for all architecture and endianness settings?
> And wouldn't it be better to use one of the get_unaligned_XXX functions
> here?

The mac address in the p_tcp structure takes mac in the reverse order as 
in p_conn. A for loop, or 3 swab16p for each copy would also do, will make 
that change.

> 
> > +		p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
> > +
> > +		p_tcp->flags = p_conn->tcp_flags;
> > +		p_tcp->ip_version = p_conn->ip_version;
> > +		for (i = 0; i < 4; i++) {
> > +			dval = p_conn->remote_ip[i];
> > +			p_tcp->remote_ip[i] = cpu_to_le32(dval);
> > +			dval = p_conn->local_ip[i];
> > +			p_tcp->local_ip[i] = cpu_to_le32(dval);
> > +		}
> > +		p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
> > +		p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
> > +
> > +		p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
> > +		p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
> > +		p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
> > +		p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
> > +		p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
> > +		p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
> > +		p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
> > +		p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
> > +		p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
> > +		p_tcp->srtt = cpu_to_le16(p_conn->srtt);
> > +		p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
> > +		p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
> > +		p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
> > +		p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
> > +		p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
> > +		dval = p_conn->ka_timeout_delta;
> > +		p_tcp->ka_timeout_delta = cpu_to_le32(dval);
> > +		dval = p_conn->rt_timeout_delta;
> > +		p_tcp->rt_timeout_delta = cpu_to_le32(dval);
> > +		p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
> > +		p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
> > +		p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
> > +		p_tcp->rt_cnt = p_conn->rt_cnt;
> > +		p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
> > +		p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
> > +		p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
> > +		p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
> > +		dval = p_conn->initial_rcv_wnd;
> > +		p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
> > +		p_tcp->ttl = p_conn->ttl;
> > +		p_tcp->tos_or_tc = p_conn->tos_or_tc;
> > +		p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
> > +		p_tcp->local_port = cpu_to_le16(p_conn->local_port);
> > +		p_tcp->mss = cpu_to_le16(p_conn->mss);
> > +		p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
> > +		p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> > +		dval = p_conn->ts_ticks_per_second;
> > +		p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
> > +		wval = p_conn->da_timeout_value;
> > +		p_tcp->da_timeout_value = cpu_to_le16(wval);
> > +		p_tcp->ack_frequency = p_conn->ack_frequency;
> > +		p_tcp->connect_mode = p_conn->connect_mode;
> > +	} else {
> > +		p_tcp2 =
> > +		    &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
> > +		ucval = p_conn->local_mac[1];
> > +		((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->local_mac[0];
> > +		((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->local_mac[3];
> > +		((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->local_mac[2];
> > +		((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->local_mac[5];
> > +		((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->local_mac[4];
> > +		((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
> > +
> > +		ucval = p_conn->remote_mac[1];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->remote_mac[0];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->remote_mac[3];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->remote_mac[2];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->remote_mac[5];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->remote_mac[4];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
> > +
> Same here.

Noted.

> 
> > +		p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);

-- snip --

> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> > new file mode 100644
> > index 0000000..269848c
> > --- /dev/null
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> > @@ -0,0 +1,52 @@
> > +/* QLogic qed NIC Driver
> > + * Copyright (c) 2015 QLogic Corporation
> > + *
> > + * This software is available 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.
> > + */
> > +
> > +#ifndef _QED_ISCSI_H
> > +#define _QED_ISCSI_H
> > +#include <linux/types.h>
> > +#include <linux/list.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/qed/tcp_common.h>
> > +#include <linux/qed/qed_iscsi_if.h>
> > +#include <linux/qed/qed_chain.h>
> > +#include "qed.h"
> > +#include "qed_hsi.h"
> > +#include "qed_mcp.h"
> > +#include "qed_sp.h"
> > +
> > +struct qed_iscsi_info {
> > +	spinlock_t lock;
> > +	struct list_head free_list;
> > +	u16 max_num_outstanding_tasks;
> > +	void *event_context;
> > +	iscsi_event_cb_t event_cb;
> > +};
> > +
> > +#ifdef CONFIG_QED_LL2
> > +extern const struct qed_ll2_ops qed_ll2_ops_pass;
> > +#endif
> > +
> > +#if IS_ENABLED(CONFIG_QEDI)
> > +struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn);
> > +
> > +void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> > +		     struct qed_iscsi_info *p_iscsi_info);
> > +
> > +void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> > +		    struct qed_iscsi_info *p_iscsi_info);
> > +#else /* IS_ENABLED(CONFIG_QEDI) */
> > +static inline struct qed_iscsi_info *qed_iscsi_alloc(
> > +		struct qed_hwfn *p_hwfn) { return NULL; }
> > +static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> > +		struct qed_iscsi_info *p_iscsi_info) {}
> > +static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> > +		struct qed_iscsi_info *p_iscsi_info) {}
> > +#endif /* IS_ENABLED(CONFIG_QEDI) */
> > +
> > +#endif
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> > index ddd410a..07e2f77 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> > @@ -2187,6 +2187,5 @@ const struct qed_eth_ops *qed_get_eth_ops(void)
> >  
> >  void qed_put_eth_ops(void)
> >  {
> > -	/* TODO - reference count for module? */
> >  }
> >  EXPORT_SYMBOL(qed_put_eth_ops);
> >
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> > index a6db107..e67f3c9 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> > @@ -299,6 +299,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
> >  		p_tx->cur_completing_bd_idx = 1;
> >  		b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
> >  		tx_frag = p_pkt->bds_set[0].tx_frag;
> > +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> >  		if (p_ll2_conn->gsi_enable)
> >  			qed_ll2b_release_tx_gsi_packet(p_hwfn,
> >  						       p_ll2_conn->my_id,
> > @@ -307,6 +308,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
> >  						       b_last_frag,
> >  						       b_last_packet);
> >  		else
> > +#endif
> >  			qed_ll2b_complete_tx_packet(p_hwfn,
> >  						    p_ll2_conn->my_id,
> >  						    p_pkt->cookie,
> Huh? What is that doing here?
> 

This is the infiniband part of the common module. The "#if" was to
prevent a compile error when infiniband part was not used (like
for this, iSCSI).

BTW, there is another patch that was submitted by Yuval M. to fix
that, this RFC just came in between. We will be pulling in that
change for the next series.

> > @@ -367,6 +369,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> >  
> >  		spin_unlock_irqrestore(&p_tx->lock, flags);
> >  		tx_frag = p_pkt->bds_set[0].tx_frag;
> > +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> >  		if (p_ll2_conn->gsi_enable)
> >  			qed_ll2b_complete_tx_gsi_packet(p_hwfn,
> >  							p_ll2_conn->my_id,
> > @@ -374,6 +377,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> >  							tx_frag,
> >  							b_last_frag, !num_bds);
> >  		else
> > +#endif
> >  			qed_ll2b_complete_tx_packet(p_hwfn,
> >  						    p_ll2_conn->my_id,
> >  						    p_pkt->cookie,
> > @@ -421,6 +425,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> >  			  "Mismatch between active_descq and the LL2 Rx chain\n");
> >  	list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
> >  
> > +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> >  	spin_unlock_irqrestore(&p_rx->lock, lock_flags);
> >  	qed_ll2b_complete_rx_gsi_packet(p_hwfn,
> >  					p_ll2_info->my_id,
> > @@ -433,6 +438,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> >  					src_mac_addrhi,
> >  					src_mac_addrlo, b_last_cqe);
> >  	spin_lock_irqsave(&p_rx->lock, lock_flags);
> > +#endif
> >  
> >  	return 0;
> >  }
> > @@ -1516,11 +1522,12 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev,
> >  
> >  static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> >  {
> > -	struct qed_ll2_info ll2_info;
> > +	struct qed_ll2_info *ll2_info;
> >  	struct qed_ll2_buffer *buffer;
> >  	enum qed_ll2_conn_type conn_type;
> >  	struct qed_ptt *p_ptt;
> >  	int rc, i;
> > +	u8 gsi_enable = 1;
> >  
> >  	/* Initialize LL2 locks & lists */
> >  	INIT_LIST_HEAD(&cdev->ll2->list);
> > @@ -1552,6 +1559,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> >  	switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
> >  	case QED_PCI_ISCSI:
> >  		conn_type = QED_LL2_TYPE_ISCSI;
> > +		gsi_enable = 0;
> >  		break;
> >  	case QED_PCI_ETH_ROCE:
> >  		conn_type = QED_LL2_TYPE_ROCE;
> > @@ -1561,18 +1569,23 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> >  	}
> >  
> >  	/* Prepare the temporary ll2 information */
> > -	memset(&ll2_info, 0, sizeof(ll2_info));
> > -	ll2_info.conn_type = conn_type;
> > -	ll2_info.mtu = params->mtu;
> > -	ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
> > -	ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
> > -	ll2_info.tx_tc = 0;
> > -	ll2_info.tx_dest = CORE_TX_DEST_NW;
> > -	ll2_info.gsi_enable = 1;
> > -
> > -	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
> > +	ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
> > +	if (!ll2_info) {
> > +		DP_INFO(cdev, "Failed to allocate LL2 info buffer\n");
> > +		goto fail;
> > +	}
> > +	ll2_info->conn_type = conn_type;
> > +	ll2_info->mtu = params->mtu;
> > +	ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
> > +	ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
> > +	ll2_info->tx_tc = 0;
> > +	ll2_info->tx_dest = CORE_TX_DEST_NW;
> > +	ll2_info->gsi_enable = gsi_enable;
> > +
> > +	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), ll2_info,
> >  					QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
> >  					&cdev->ll2->handle);
> > +	kfree(ll2_info);
> >  	if (rc) {
> >  		DP_INFO(cdev, "Failed to acquire LL2 connection\n");
> >  		goto fail;
> Where is the benefit of this hunk? And is it related to iSCSI?

This hunk was to prevent a large stack warning (was present with
gcc 4.8.3). This is a common function applicable to iSCSI as well.

> 
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
> > index 4ee3151..a01ad9d 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_main.c
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
> > @@ -1239,7 +1239,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
> >  	if (link.link_up)
> >  		if_link->link_up = true;
> >  
> > -	/* TODO - at the moment assume supported and advertised speed equal */
> >  	if_link->supported_caps = QED_LM_FIBRE_BIT;
> >  	if (params.speed.autoneg)
> >  		if_link->supported_caps |= QED_LM_Autoneg_BIT;
> > @@ -1294,7 +1293,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
> >  	if (link.link_up)
> >  		if_link->speed = link.speed;
> >  
> > -	/* TODO - fill duplex properly */
> >  	if_link->duplex = DUPLEX_FULL;
> >  	qed_mcp_get_media_type(hwfn->cdev, &media_type);
> >  	if_link->port = qed_get_port_type(media_type);
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> > index dff520e..2e5f51b 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> > @@ -314,9 +314,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
> >  
> >  /* Using hwfn number (and not pf_num) is required since in CMT mode,
> >   * same pf_num may be used by two different hwfn
> > - * TODO - this shouldn't really be in .h file, but until all fields
> > - * required during hw-init will be placed in their correct place in shmem
> > - * we need it in qed_dev.c [for readin the nvram reflection in shmem].
> >   */
> >  #define MCP_PF_ID_BY_REL(p_hwfn, rel_pfid) (QED_IS_BB((p_hwfn)->cdev) ?	       \
> >  					    ((rel_pfid) |		       \
> > @@ -324,9 +321,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
> >  					    rel_pfid)
> >  #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id)
> >  
> > -/* TODO - this is only correct as long as only BB is supported, and
> > - * no port-swapping is implemented; Afterwards we'll need to fix it.
> > - */
> >  #define MFW_PORT(_p_hwfn)       ((_p_hwfn)->abs_pf_id %	\
> >  				 ((_p_hwfn)->cdev->num_ports_in_engines * 2))
> >  struct qed_mcp_info {
> Please split off the patch and use a separate one to remove all the TODO
> entries. They do not relate to the iSCSI offload bit.
> 

Will do.

> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> > index b414a05..9754420 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> > @@ -82,6 +82,8 @@
> >  	0x1c80000UL
> >  #define BAR0_MAP_REG_XSDM_RAM \
> >  	0x1e00000UL
> > +#define BAR0_MAP_REG_YSDM_RAM \
> > +	0x1e80000UL
> >  #define  NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
> >  	0x5011f4UL
> >  #define  PRS_REG_SEARCH_TCP \
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> > index caff415..d3fa578 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
> > +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> > @@ -24,6 +24,7 @@
> >  #include "qed_hsi.h"
> >  #include "qed_hw.h"
> >  #include "qed_int.h"
> > +#include "qed_iscsi.h"
> >  #include "qed_mcp.h"
> >  #include "qed_reg_addr.h"
> >  #include "qed_sp.h"
> > @@ -249,6 +250,20 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
> >  		return qed_sriov_eqe_event(p_hwfn,
> >  					   p_eqe->opcode,
> >  					   p_eqe->echo, &p_eqe->data);
> > +	case PROTOCOLID_ISCSI:
> > +		if (!IS_ENABLED(CONFIG_QEDI))
> > +			return -EINVAL;
> > +
> > +		if (p_hwfn->p_iscsi_info->event_cb) {
> > +			struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info;
> > +
> > +			return p_iscsi->event_cb(p_iscsi->event_context,
> > +						 p_eqe->opcode, &p_eqe->data);
> > +		} else {
> > +			DP_NOTICE(p_hwfn,
> > +				  "iSCSI async completion is not set\n");
> > +			return -EINVAL;
> > +		}
> >  	default:
> >  		DP_NOTICE(p_hwfn,
> >  			  "Unknown Async completion for protocol: %d\n",
> > diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
> > index f9ae903..c0c9fa8 100644
> > --- a/include/linux/qed/qed_if.h
> > +++ b/include/linux/qed/qed_if.h
> > @@ -165,6 +165,7 @@ struct qed_iscsi_pf_params {
> >  	u32 max_cwnd;
> >  	u16 cq_num_entries;
> >  	u16 cmdq_num_entries;
> > +	u32 two_msl_timer;
> >  	u16 dup_ack_threshold;
> >  	u16 tx_sws_timer;
> >  	u16 min_rto;
> > @@ -271,6 +272,7 @@ struct qed_dev_info {
> >  enum qed_sb_type {
> >  	QED_SB_TYPE_L2_QUEUE,
> >  	QED_SB_TYPE_CNQ,
> > +	QED_SB_TYPE_STORAGE,
> >  };
> >  
> >  enum qed_protocol {
> > diff --git a/include/linux/qed/qed_iscsi_if.h b/include/linux/qed/qed_iscsi_if.h
> > new file mode 100644
> > index 0000000..6735ee5
> > --- /dev/null
> > +++ b/include/linux/qed/qed_iscsi_if.h
> > @@ -0,0 +1,249 @@
> > +/* QLogic qed NIC Driver
> Again, this is the iSCSI driver, is it not?
> 
> > + * Copyright (c) 2015 QLogic Corporation
> > + *
> And you _might_ want to check the copyright, seeing that it's being
> posted from the cavium.com domain ...
> 

Yes, rest of the files (already existing) for qed has the same
copyright, so this patch did not modify it. qedi, OTOH, has all
new files and are using the updated ones. A new patch will be
posted to update the qed files.

Regards,
-Arun
Arun Easi Oct. 20, 2016, 12:14 a.m. UTC | #4
Thanks Johannes for the review, please see my response below.

On Wed, 19 Oct 2016, 2:09am, Johannes Thumshirn wrote:

> Hi Manish,
> 
> Some initital comments
> 
> On Wed, Oct 19, 2016 at 01:01:08AM -0400, manish.rangankar@cavium.com wrote:
> > From: Yuval Mintz <Yuval.Mintz@qlogic.com>
> > 
> > This adds the backbone required for the various HW initalizations
> > which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
> > 4xxxx line of adapters - FW notification, resource initializations, etc.
> > 
> > Signed-off-by: Arun Easi <arun.easi@cavium.com>
> > Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
> > ---
> >  drivers/net/ethernet/qlogic/Kconfig            |   15 +
> >  drivers/net/ethernet/qlogic/qed/Makefile       |    1 +
> >  drivers/net/ethernet/qlogic/qed/qed.h          |    8 +-
> >  drivers/net/ethernet/qlogic/qed/qed_dev.c      |   15 +
> >  drivers/net/ethernet/qlogic/qed/qed_int.h      |    1 -
> >  drivers/net/ethernet/qlogic/qed/qed_iscsi.c    | 1310 ++++++++++++++++++++++++
> >  drivers/net/ethernet/qlogic/qed/qed_iscsi.h    |   52 +
> >  drivers/net/ethernet/qlogic/qed/qed_l2.c       |    1 -
> >  drivers/net/ethernet/qlogic/qed/qed_ll2.c      |   35 +-
> >  drivers/net/ethernet/qlogic/qed/qed_main.c     |    2 -
> >  drivers/net/ethernet/qlogic/qed/qed_mcp.h      |    6 -
> >  drivers/net/ethernet/qlogic/qed/qed_reg_addr.h |    2 +
> >  drivers/net/ethernet/qlogic/qed/qed_spq.c      |   15 +
> >  include/linux/qed/qed_if.h                     |    2 +
> >  include/linux/qed/qed_iscsi_if.h               |  249 +++++
> >  15 files changed, 1692 insertions(+), 22 deletions(-)
> >  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> >  create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> >  create mode 100644 include/linux/qed/qed_iscsi_if.h
> > 
> > diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
> > index 0df1391f9..bad4fae 100644
> > --- a/drivers/net/ethernet/qlogic/Kconfig
> > +++ b/drivers/net/ethernet/qlogic/Kconfig
> > @@ -118,4 +118,19 @@ config INFINIBAND_QEDR
> >  	  for QLogic QED. This would be replaced by the 'real' option
> >  	  once the QEDR driver is added [+relocated].
> >  
> > +config QED_ISCSI
> > +	bool
> > +
> > +config QEDI
> > +	tristate "QLogic QED 25/40/100Gb iSCSI driver"
> > +	depends on QED
> > +	select QED_LL2
> > +	select QED_ISCSI
> > +	default n
> > +	---help---
> > +	  This provides a temporary node that allows the compilation
> > +	  and logical testing of the hardware offload iSCSI support
> > +	  for QLogic QED. This would be replaced by the 'real' option
> > +	  once the QEDI driver is added [+relocated].
> > +
> >  endif # NET_VENDOR_QLOGIC
> > diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
> > index cda0af7..b76669c 100644
> > --- a/drivers/net/ethernet/qlogic/qed/Makefile
> > +++ b/drivers/net/ethernet/qlogic/qed/Makefile
> > @@ -6,3 +6,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
> >  qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
> >  qed-$(CONFIG_QED_LL2) += qed_ll2.o
> >  qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
> > +qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
> > diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
> > index 653bb57..a61b1c0 100644
> > --- a/drivers/net/ethernet/qlogic/qed/qed.h
> > +++ b/drivers/net/ethernet/qlogic/qed/qed.h
> > @@ -35,6 +35,7 @@
> >  
> >  #define QED_WFQ_UNIT	100
> >  
> > +#define ISCSI_BDQ_ID(_port_id) (_port_id)
> 
> This looks a bit odd to me.
> 
> [...]
> 
> >  #endif
> > +		if (IS_ENABLED(CONFIG_QEDI) &&
> > +				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> > +			qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);
> 
> 
> Why not introduce a small helper like:
> static inline bool qed_is_iscsi_personality()
> {
> 	return IS_ENABLED(CONFIG_QEDI) && p_hwfn->hw_info.personality ==
> 		QED_PCI_ISCSI;
> }

I think I can remove the IS_ENABLED() check in places like this
and have the check contained in header file. qed_iscsi_free()
already is taken care, if I do the same fore qed_ooo*, I think
the check would just be "p_hwfn->hw_info.personality ==
QED_PCI_ISCSI", which would keep it consistent with the other
areas where similar check is done for other protocols.

> 
> >  		qed_iov_free(p_hwfn);
> 
> [...]
> 
> > +
> > +	if (!GET_FIELD(p_ramrod->iscsi.flags,
> > +		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> > +		p_tcp = &p_ramrod->tcp;
> > +		ucval = p_conn->local_mac[1];
> > +		((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->local_mac[0];
> > +		((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->local_mac[3];
> > +		((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->local_mac[2];
> > +		((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->local_mac[5];
> > +		((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->local_mac[4];
> > +		((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
> > +		ucval = p_conn->remote_mac[1];
> > +		((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->remote_mac[0];
> > +		((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->remote_mac[3];
> > +		((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->remote_mac[2];
> > +		((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->remote_mac[5];
> > +		((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->remote_mac[4];
> > +		((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
> > +
> > +		p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
> > +
> > +		p_tcp->flags = p_conn->tcp_flags;
> > +		p_tcp->ip_version = p_conn->ip_version;
> > +		for (i = 0; i < 4; i++) {
> > +			dval = p_conn->remote_ip[i];
> > +			p_tcp->remote_ip[i] = cpu_to_le32(dval);
> > +			dval = p_conn->local_ip[i];
> > +			p_tcp->local_ip[i] = cpu_to_le32(dval);
> > +		}
> > +		p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
> > +		p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
> > +
> > +		p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
> > +		p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
> > +		p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
> > +		p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
> > +		p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
> > +		p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
> > +		p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
> > +		p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
> > +		p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
> > +		p_tcp->srtt = cpu_to_le16(p_conn->srtt);
> > +		p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
> > +		p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
> > +		p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
> > +		p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
> > +		p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
> > +		dval = p_conn->ka_timeout_delta;
> > +		p_tcp->ka_timeout_delta = cpu_to_le32(dval);
> > +		dval = p_conn->rt_timeout_delta;
> > +		p_tcp->rt_timeout_delta = cpu_to_le32(dval);
> > +		p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
> > +		p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
> > +		p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
> > +		p_tcp->rt_cnt = p_conn->rt_cnt;
> > +		p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
> > +		p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
> > +		p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
> > +		p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
> > +		dval = p_conn->initial_rcv_wnd;
> > +		p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
> > +		p_tcp->ttl = p_conn->ttl;
> > +		p_tcp->tos_or_tc = p_conn->tos_or_tc;
> > +		p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
> > +		p_tcp->local_port = cpu_to_le16(p_conn->local_port);
> > +		p_tcp->mss = cpu_to_le16(p_conn->mss);
> > +		p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
> > +		p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> > +		dval = p_conn->ts_ticks_per_second;
> > +		p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
> > +		wval = p_conn->da_timeout_value;
> > +		p_tcp->da_timeout_value = cpu_to_le16(wval);
> > +		p_tcp->ack_frequency = p_conn->ack_frequency;
> > +		p_tcp->connect_mode = p_conn->connect_mode;
> > +	} else {
> > +		p_tcp2 =
> > +		    &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
> > +		ucval = p_conn->local_mac[1];
> > +		((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->local_mac[0];
> > +		((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->local_mac[3];
> > +		((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->local_mac[2];
> > +		((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->local_mac[5];
> > +		((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->local_mac[4];
> > +		((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
> > +
> > +		ucval = p_conn->remote_mac[1];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
> > +		ucval = p_conn->remote_mac[0];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
> > +		ucval = p_conn->remote_mac[3];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
> > +		ucval = p_conn->remote_mac[2];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
> > +		ucval = p_conn->remote_mac[5];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
> > +		ucval = p_conn->remote_mac[4];
> > +		((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
> > +
> > +		p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);
> > +		p_tcp2->flags = p_conn->tcp_flags;
> > +
> > +		p_tcp2->ip_version = p_conn->ip_version;
> > +		for (i = 0; i < 4; i++) {
> > +			dval = p_conn->remote_ip[i];
> > +			p_tcp2->remote_ip[i] = cpu_to_le32(dval);
> > +			dval = p_conn->local_ip[i];
> > +			p_tcp2->local_ip[i] = cpu_to_le32(dval);
> > +		}
> > +
> > +		p_tcp2->flow_label = cpu_to_le32(p_conn->flow_label);
> > +		p_tcp2->ttl = p_conn->ttl;
> > +		p_tcp2->tos_or_tc = p_conn->tos_or_tc;
> > +		p_tcp2->remote_port = cpu_to_le16(p_conn->remote_port);
> > +		p_tcp2->local_port = cpu_to_le16(p_conn->local_port);
> > +		p_tcp2->mss = cpu_to_le16(p_conn->mss);
> > +		p_tcp2->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> > +		p_tcp2->connect_mode = p_conn->connect_mode;
> > +		wval = p_conn->syn_ip_payload_length;
> > +		p_tcp2->syn_ip_payload_length = cpu_to_le16(wval);
> > +		p_tcp2->syn_phy_addr_lo = DMA_LO_LE(p_conn->syn_phy_addr);
> > +		p_tcp2->syn_phy_addr_hi = DMA_HI_LE(p_conn->syn_phy_addr);
> > +	}
> 
> Is there any chance you could factor out above blocks into own functions so
> you have
> 
> 
> 	if (!GET_FIELD(p_ramrod->iscsi.flags,
> 		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> 		qedi_do_stuff_off_chip();
> 	else 
> 		qedi_do_stuff_on_chip();
> 

This function mostly fills data needed for the firmware interface.
By having all data necessary for the command
ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN in this function it is easier to
refer what is being fed to firmware. If you do not have strong
objections, I would like to keep it this way.

> > +
> 
> [...]
> 
> > +static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
> > +{
> > +	return (u8 __iomem *)p_hwfn->doorbells +
> > +			     qed_db_addr(cid, DQ_DEMS_LEGACY);
> > +}
> > +
> > +static void __iomem *qed_iscsi_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
> > +						    u8 bdq_id)
> > +{
> > +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> > +
> > +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
> > +			     MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> > +							     bdq_id);
> > +}
> > +
> > +static void __iomem *qed_iscsi_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
> > +						      u8 bdq_id)
> > +{
> > +	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> > +
> > +	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
> > +			     TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> > +							     bdq_id);
> > +}
> 
> Why are you casting to u8* here, you're returning void*? 
> 

The cast is for the "p_hwfn->regview".

> [...]
> 
> > +
> > +	if (tasks) {
> > +		struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
> > +						       GFP_KERNEL);
> > +
> > +		if (!tid_info) {
> > +			DP_NOTICE(cdev,
> > +				  "Failed to allocate tasks information\n");
> > +			qed_iscsi_stop(cdev);
> > +			return -ENOMEM;
> > +		}
> > +
> > +		rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
> > +					      tid_info);
> > +		if (rc) {
> > +			DP_NOTICE(cdev, "Failed to gather task information\n");
> > +			qed_iscsi_stop(cdev);
> > +			kfree(tid_info);
> > +			return rc;
> > +		}
> > +
> > +		/* Fill task information */
> > +		tasks->size = tid_info->tid_size;
> > +		tasks->num_tids_per_block = tid_info->num_tids_per_block;
> > +		memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
> > +
> > +		kfree(tid_info);
> > +	}
> > +
> > +	return 0;
> > +}
> 
> Maybe:
> 
> struct qed_tid_mem *tid_info;
> [...]
> if (!tasks)
> 	return 0;
> 
> tid_info = kzalloc(sizeof(*tid_info), GFP_KERNEL);
> 
> if (!tid_info) {
> 	DP_NOTICE(cdev, "Failed to allocate tasks information\n");
> 	qed_iscsi_stop(cdev);
> 	return -ENOMEM;
> }
> 
> rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev), tid_info);
> if (rc) {
> 	DP_NOTICE(cdev, "Failed to gather task information\n");
> 	qed_iscsi_stop(cdev);
> 	kfree(tid_info);
> 	return rc;
> }
> 
> /* Fill task information */
> tasks->size = tid_info->tid_size;
> tasks->num_tids_per_block = tid_info->num_tids_per_block;
> memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
> 
> kfree(tid_info);
> 

Sure, will do.

> > +
> 
> [...]
> 
> > +/**
> > + * @brief start iscsi in FW
> > + *
> > + * @param cdev
> > + * @param tasks - qed will fill information about tasks
> > + *
> 
> Please use proper kerneldoc and not doxygen syntax.
> 

Sure, will do.

Regards,
-Arun
Johannes Thumshirn Oct. 20, 2016, 7:09 a.m. UTC | #5
Hi Arun,

On Wed, Oct 19, 2016 at 05:14:59PM -0700, Arun Easi wrote:
> Thanks Johannes for the review, please see my response below.
> 

[...]

> > 
> > Why not introduce a small helper like:
> > static inline bool qed_is_iscsi_personality()
> > {
> > 	return IS_ENABLED(CONFIG_QEDI) && p_hwfn->hw_info.personality ==
> > 		QED_PCI_ISCSI;
> > }
> 
> I think I can remove the IS_ENABLED() check in places like this
> and have the check contained in header file. qed_iscsi_free()
> already is taken care, if I do the same fore qed_ooo*, I think
> the check would just be "p_hwfn->hw_info.personality ==
> QED_PCI_ISCSI", which would keep it consistent with the other
> areas where similar check is done for other protocols.

Sounds good.

> 

[...]

> > 
> > Is there any chance you could factor out above blocks into own functions so
> > you have
> > 
> > 
> > 	if (!GET_FIELD(p_ramrod->iscsi.flags,
> > 		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> > 		qedi_do_stuff_off_chip();
> > 	else 
> > 		qedi_do_stuff_on_chip();
> > 
> 
> This function mostly fills data needed for the firmware interface.
> By having all data necessary for the command
> ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN in this function it is easier to
> refer what is being fed to firmware. If you do not have strong
> objections, I would like to keep it this way.

No strong objections, I just don't think these lengthy blocks are readable,
but I don't want to do too much bikeshedding about it.

Thanks,
	Johannes
diff mbox

Patch

diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index 0df1391f9..bad4fae 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -118,4 +118,19 @@  config INFINIBAND_QEDR
 	  for QLogic QED. This would be replaced by the 'real' option
 	  once the QEDR driver is added [+relocated].
 
+config QED_ISCSI
+	bool
+
+config QEDI
+	tristate "QLogic QED 25/40/100Gb iSCSI driver"
+	depends on QED
+	select QED_LL2
+	select QED_ISCSI
+	default n
+	---help---
+	  This provides a temporary node that allows the compilation
+	  and logical testing of the hardware offload iSCSI support
+	  for QLogic QED. This would be replaced by the 'real' option
+	  once the QEDI driver is added [+relocated].
+
 endif # NET_VENDOR_QLOGIC
diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
index cda0af7..b76669c 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -6,3 +6,4 @@  qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
 qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
 qed-$(CONFIG_QED_LL2) += qed_ll2.o
 qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
+qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index 653bb57..a61b1c0 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -35,6 +35,7 @@ 
 
 #define QED_WFQ_UNIT	100
 
+#define ISCSI_BDQ_ID(_port_id) (_port_id)
 #define QED_WID_SIZE            (1024)
 #define QED_PF_DEMS_SIZE        (4)
 
@@ -167,6 +168,7 @@  enum QED_RESOURCES {
 	QED_ILT,
 	QED_LL2_QUEUE,
 	QED_RDMA_STATS_QUEUE,
+	QED_CMDQS_CQS,
 	QED_MAX_RESC,
 };
 
@@ -379,6 +381,7 @@  struct qed_hwfn {
 	bool				using_ll2;
 	struct qed_ll2_info		*p_ll2_info;
 	struct qed_rdma_info		*p_rdma_info;
+	struct qed_iscsi_info		*p_iscsi_info;
 	struct qed_pf_params		pf_params;
 
 	bool b_rdma_enabled_in_prs;
@@ -578,6 +581,8 @@  struct qed_dev {
 	/* Linux specific here */
 	struct  qede_dev		*edev;
 	struct  pci_dev			*pdev;
+	u32 flags;
+#define QED_FLAG_STORAGE_STARTED	(BIT(0))
 	int				msg_enable;
 
 	struct pci_params		pci_params;
@@ -591,6 +596,7 @@  struct qed_dev {
 	union {
 		struct qed_common_cb_ops	*common;
 		struct qed_eth_cb_ops		*eth;
+		struct qed_iscsi_cb_ops		*iscsi;
 	} protocol_ops;
 	void				*ops_cookie;
 
@@ -600,7 +606,7 @@  struct qed_dev {
 	struct qed_cb_ll2_info		*ll2;
 	u8				ll2_mac_address[ETH_ALEN];
 #endif
-
+	DECLARE_HASHTABLE(connections, 10);
 	const struct firmware		*firmware;
 
 	u32 rdma_max_sge;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 754f6a9..a4234c0 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -29,6 +29,7 @@ 
 #include "qed_hw.h"
 #include "qed_init_ops.h"
 #include "qed_int.h"
+#include "qed_iscsi.h"
 #include "qed_ll2.h"
 #include "qed_mcp.h"
 #include "qed_reg_addr.h"
@@ -155,6 +156,9 @@  void qed_resc_free(struct qed_dev *cdev)
 #ifdef CONFIG_QED_LL2
 		qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info);
 #endif
+		if (IS_ENABLED(CONFIG_QEDI) &&
+				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
+			qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);
 		qed_iov_free(p_hwfn);
 		qed_dmae_info_free(p_hwfn);
 		qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
@@ -411,6 +415,7 @@  int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 
 int qed_resc_alloc(struct qed_dev *cdev)
 {
+	struct qed_iscsi_info *p_iscsi_info;
 #ifdef CONFIG_QED_LL2
 	struct qed_ll2_info *p_ll2_info;
 #endif
@@ -532,6 +537,13 @@  int qed_resc_alloc(struct qed_dev *cdev)
 			p_hwfn->p_ll2_info = p_ll2_info;
 		}
 #endif
+		if (IS_ENABLED(CONFIG_QEDI) &&
+			p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
+			p_iscsi_info = qed_iscsi_alloc(p_hwfn);
+			if (!p_iscsi_info)
+				goto alloc_no_mem;
+			p_hwfn->p_iscsi_info = p_iscsi_info;
+		}
 
 		/* DMA info initialization */
 		rc = qed_dmae_info_alloc(p_hwfn);
@@ -585,6 +597,9 @@  void qed_resc_setup(struct qed_dev *cdev)
 		if (p_hwfn->using_ll2)
 			qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info);
 #endif
+		if (IS_ENABLED(CONFIG_QEDI) &&
+				p_hwfn->hw_info.personality == QED_PCI_ISCSI)
+			qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info);
 	}
 }
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h
index 0948be6..cc28066 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_int.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_int.h
@@ -218,7 +218,6 @@  struct qed_igu_info {
 	u16			free_blks;
 };
 
-/* TODO Names of function may change... */
 void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn,
 			      struct qed_ptt *p_ptt,
 			      bool b_set,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
new file mode 100644
index 0000000..cb22dad
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -0,0 +1,1310 @@ 
+/* QLogic qed NIC Driver
+ * Copyright (c) 2015 QLogic Corporation
+ *
+ * This software is available 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.
+ */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/param.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/qed/qed_iscsi_if.h>
+#include "qed.h"
+#include "qed_cxt.h"
+#include "qed_dev_api.h"
+#include "qed_hsi.h"
+#include "qed_hw.h"
+#include "qed_int.h"
+#include "qed_iscsi.h"
+#include "qed_ll2.h"
+#include "qed_mcp.h"
+#include "qed_sp.h"
+#include "qed_sriov.h"
+#include "qed_reg_addr.h"
+
+struct qed_iscsi_conn {
+	struct list_head list_entry;
+	bool free_on_delete;
+
+	u16 conn_id;
+	u32 icid;
+	u32 fw_cid;
+
+	u8 layer_code;
+	u8 offl_flags;
+	u8 connect_mode;
+	u32 initial_ack;
+	dma_addr_t sq_pbl_addr;
+	struct qed_chain r2tq;
+	struct qed_chain xhq;
+	struct qed_chain uhq;
+
+	struct tcp_upload_params *tcp_upload_params_virt_addr;
+	dma_addr_t tcp_upload_params_phys_addr;
+	struct scsi_terminate_extra_params *queue_cnts_virt_addr;
+	dma_addr_t queue_cnts_phys_addr;
+	dma_addr_t syn_phy_addr;
+
+	u16 syn_ip_payload_length;
+	u8 local_mac[6];
+	u8 remote_mac[6];
+	u16 vlan_id;
+	u8 tcp_flags;
+	u8 ip_version;
+	u32 remote_ip[4];
+	u32 local_ip[4];
+	u8 ka_max_probe_cnt;
+	u8 dup_ack_theshold;
+	u32 rcv_next;
+	u32 snd_una;
+	u32 snd_next;
+	u32 snd_max;
+	u32 snd_wnd;
+	u32 rcv_wnd;
+	u32 snd_wl1;
+	u32 cwnd;
+	u32 ss_thresh;
+	u16 srtt;
+	u16 rtt_var;
+	u32 ts_time;
+	u32 ts_recent;
+	u32 ts_recent_age;
+	u32 total_rt;
+	u32 ka_timeout_delta;
+	u32 rt_timeout_delta;
+	u8 dup_ack_cnt;
+	u8 snd_wnd_probe_cnt;
+	u8 ka_probe_cnt;
+	u8 rt_cnt;
+	u32 flow_label;
+	u32 ka_timeout;
+	u32 ka_interval;
+	u32 max_rt_time;
+	u32 initial_rcv_wnd;
+	u8 ttl;
+	u8 tos_or_tc;
+	u16 remote_port;
+	u16 local_port;
+	u16 mss;
+	u8 snd_wnd_scale;
+	u8 rcv_wnd_scale;
+	u32 ts_ticks_per_second;
+	u16 da_timeout_value;
+	u8 ack_frequency;
+
+	u8 update_flag;
+	u8 default_cq;
+	u32 max_seq_size;
+	u32 max_recv_pdu_length;
+	u32 max_send_pdu_length;
+	u32 first_seq_length;
+	u32 exp_stat_sn;
+	u32 stat_sn;
+	u16 physical_q0;
+	u16 physical_q1;
+	u8 abortive_dsconnect;
+};
+
+static int
+qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
+			enum spq_mode comp_mode,
+			struct qed_spq_comp_cb *p_comp_addr,
+			void *event_context, iscsi_event_cb_t async_event_cb)
+{
+	struct iscsi_init_ramrod_params *p_ramrod = NULL;
+	struct scsi_init_func_queues *p_queue = NULL;
+	struct qed_iscsi_pf_params *p_params = NULL;
+	struct iscsi_spe_func_init *p_init = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	int rc = 0;
+	u32 dval;
+	u16 val;
+	u8 i;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = qed_spq_get_cid(p_hwfn);
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_INIT_FUNC,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_init;
+	p_init = &p_ramrod->iscsi_init_spe;
+	p_params = &p_hwfn->pf_params.iscsi_pf_params;
+	p_queue = &p_init->q_params;
+
+	SET_FIELD(p_init->hdr.flags,
+		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, ISCSI_SLOW_PATH_LAYER_CODE);
+	p_init->hdr.op_code = ISCSI_RAMROD_CMD_ID_INIT_FUNC;
+
+	val = p_params->half_way_close_timeout;
+	p_init->half_way_close_timeout = cpu_to_le16(val);
+	p_init->num_sq_pages_in_ring = p_params->num_sq_pages_in_ring;
+	p_init->num_r2tq_pages_in_ring = p_params->num_r2tq_pages_in_ring;
+	p_init->num_uhq_pages_in_ring = p_params->num_uhq_pages_in_ring;
+	p_init->func_params.log_page_size = p_params->log_page_size;
+	val = p_params->num_tasks;
+	p_init->func_params.num_tasks = cpu_to_le16(val);
+	p_init->debug_mode.flags = p_params->debug_mode;
+
+	DMA_REGPAIR_LE(p_queue->glbl_q_params_addr,
+		       p_params->glbl_q_params_addr);
+
+	val = p_params->cq_num_entries;
+	p_queue->cq_num_entries = cpu_to_le16(val);
+	val = p_params->cmdq_num_entries;
+	p_queue->cmdq_num_entries = cpu_to_le16(val);
+	p_queue->num_queues = p_params->num_queues;
+	dval = (u8)p_hwfn->hw_info.resc_start[QED_CMDQS_CQS];
+	p_queue->queue_relative_offset = (u8)dval;
+	p_queue->cq_sb_pi = p_params->gl_rq_pi;
+	p_queue->cmdq_sb_pi = p_params->gl_cmd_pi;
+
+	for (i = 0; i < p_params->num_queues; i++) {
+		val = p_hwfn->sbs_info[i]->igu_sb_id;
+		p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val);
+	}
+
+	p_queue->bdq_resource_id = ISCSI_BDQ_ID(p_hwfn->port_id);
+
+	DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_RQ],
+		       p_params->bdq_pbl_base_addr[BDQ_ID_RQ]);
+	p_queue->bdq_pbl_num_entries[BDQ_ID_RQ] =
+	    p_params->bdq_pbl_num_entries[BDQ_ID_RQ];
+	val = p_params->bdq_xoff_threshold[BDQ_ID_RQ];
+	p_queue->bdq_xoff_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
+	val = p_params->bdq_xon_threshold[BDQ_ID_RQ];
+	p_queue->bdq_xon_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
+
+	DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_IMM_DATA],
+		       p_params->bdq_pbl_base_addr[BDQ_ID_IMM_DATA]);
+	p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA] =
+	    p_params->bdq_pbl_num_entries[BDQ_ID_IMM_DATA];
+	val = p_params->bdq_xoff_threshold[BDQ_ID_IMM_DATA];
+	p_queue->bdq_xoff_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
+	val = p_params->bdq_xon_threshold[BDQ_ID_IMM_DATA];
+	p_queue->bdq_xon_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
+	val = p_params->rq_buffer_size;
+	p_queue->rq_buffer_size = cpu_to_le16(val);
+	if (p_params->is_target) {
+		SET_FIELD(p_queue->q_validity,
+			  SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
+		if (p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA])
+			SET_FIELD(p_queue->q_validity,
+				  SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID, 1);
+		SET_FIELD(p_queue->q_validity,
+			  SCSI_INIT_FUNC_QUEUES_CMD_VALID, 1);
+	} else {
+		SET_FIELD(p_queue->q_validity,
+			  SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
+	}
+	p_ramrod->tcp_init.two_msl_timer = cpu_to_le32(p_params->two_msl_timer);
+	val = p_params->tx_sws_timer;
+	p_ramrod->tcp_init.tx_sws_timer = cpu_to_le16(val);
+	p_ramrod->tcp_init.maxfinrt = p_params->max_fin_rt;
+
+	p_hwfn->p_iscsi_info->event_context = event_context;
+	p_hwfn->p_iscsi_info->event_cb = async_event_cb;
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn,
+				     struct qed_iscsi_conn *p_conn,
+				     enum spq_mode comp_mode,
+				     struct qed_spq_comp_cb *p_comp_addr)
+{
+	struct iscsi_spe_conn_offload *p_ramrod = NULL;
+	struct tcp_offload_params_opt2 *p_tcp2 = NULL;
+	struct tcp_offload_params *p_tcp = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	union qed_qm_pq_params pq_params;
+	u16 pq0_id = 0, pq1_id = 0;
+	dma_addr_t r2tq_pbl_addr;
+	dma_addr_t xhq_pbl_addr;
+	dma_addr_t uhq_pbl_addr;
+	int rc = 0;
+	u32 dval;
+	u16 wval;
+	u8 ucval;
+	u8 i;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = p_conn->icid;
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_conn_offload;
+
+	/* Transmission PQ is the first of the PF */
+	memset(&pq_params, 0, sizeof(pq_params));
+	pq0_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
+	p_conn->physical_q0 = cpu_to_le16(pq0_id);
+	p_ramrod->iscsi.physical_q0 = cpu_to_le16(pq0_id);
+
+	/* iSCSI Pure-ACK PQ */
+	pq_params.iscsi.q_idx = 1;
+	pq1_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
+	p_conn->physical_q1 = cpu_to_le16(pq1_id);
+	p_ramrod->iscsi.physical_q1 = cpu_to_le16(pq1_id);
+
+	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN;
+	SET_FIELD(p_ramrod->hdr.flags, ISCSI_SLOW_PATH_HDR_LAYER_CODE,
+		  p_conn->layer_code);
+
+	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
+
+	DMA_REGPAIR_LE(p_ramrod->iscsi.sq_pbl_addr, p_conn->sq_pbl_addr);
+
+	r2tq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->r2tq);
+	DMA_REGPAIR_LE(p_ramrod->iscsi.r2tq_pbl_addr, r2tq_pbl_addr);
+
+	xhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->xhq);
+	DMA_REGPAIR_LE(p_ramrod->iscsi.xhq_pbl_addr, xhq_pbl_addr);
+
+	uhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->uhq);
+	DMA_REGPAIR_LE(p_ramrod->iscsi.uhq_pbl_addr, uhq_pbl_addr);
+
+	p_ramrod->iscsi.initial_ack = cpu_to_le32(p_conn->initial_ack);
+	p_ramrod->iscsi.flags = p_conn->offl_flags;
+	p_ramrod->iscsi.default_cq = p_conn->default_cq;
+	p_ramrod->iscsi.stat_sn = cpu_to_le32(p_conn->stat_sn);
+
+	if (!GET_FIELD(p_ramrod->iscsi.flags,
+		       ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
+		p_tcp = &p_ramrod->tcp;
+		ucval = p_conn->local_mac[1];
+		((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
+		ucval = p_conn->local_mac[0];
+		((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
+		ucval = p_conn->local_mac[3];
+		((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
+		ucval = p_conn->local_mac[2];
+		((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
+		ucval = p_conn->local_mac[5];
+		((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
+		ucval = p_conn->local_mac[4];
+		((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
+		ucval = p_conn->remote_mac[1];
+		((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
+		ucval = p_conn->remote_mac[0];
+		((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
+		ucval = p_conn->remote_mac[3];
+		((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
+		ucval = p_conn->remote_mac[2];
+		((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
+		ucval = p_conn->remote_mac[5];
+		((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
+		ucval = p_conn->remote_mac[4];
+		((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
+
+		p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
+
+		p_tcp->flags = p_conn->tcp_flags;
+		p_tcp->ip_version = p_conn->ip_version;
+		for (i = 0; i < 4; i++) {
+			dval = p_conn->remote_ip[i];
+			p_tcp->remote_ip[i] = cpu_to_le32(dval);
+			dval = p_conn->local_ip[i];
+			p_tcp->local_ip[i] = cpu_to_le32(dval);
+		}
+		p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
+		p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
+
+		p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
+		p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
+		p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
+		p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
+		p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
+		p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
+		p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
+		p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
+		p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
+		p_tcp->srtt = cpu_to_le16(p_conn->srtt);
+		p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
+		p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
+		p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
+		p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
+		p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
+		dval = p_conn->ka_timeout_delta;
+		p_tcp->ka_timeout_delta = cpu_to_le32(dval);
+		dval = p_conn->rt_timeout_delta;
+		p_tcp->rt_timeout_delta = cpu_to_le32(dval);
+		p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
+		p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
+		p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
+		p_tcp->rt_cnt = p_conn->rt_cnt;
+		p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
+		p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
+		p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
+		p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
+		dval = p_conn->initial_rcv_wnd;
+		p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
+		p_tcp->ttl = p_conn->ttl;
+		p_tcp->tos_or_tc = p_conn->tos_or_tc;
+		p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
+		p_tcp->local_port = cpu_to_le16(p_conn->local_port);
+		p_tcp->mss = cpu_to_le16(p_conn->mss);
+		p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
+		p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
+		dval = p_conn->ts_ticks_per_second;
+		p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
+		wval = p_conn->da_timeout_value;
+		p_tcp->da_timeout_value = cpu_to_le16(wval);
+		p_tcp->ack_frequency = p_conn->ack_frequency;
+		p_tcp->connect_mode = p_conn->connect_mode;
+	} else {
+		p_tcp2 =
+		    &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
+		ucval = p_conn->local_mac[1];
+		((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
+		ucval = p_conn->local_mac[0];
+		((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
+		ucval = p_conn->local_mac[3];
+		((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
+		ucval = p_conn->local_mac[2];
+		((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
+		ucval = p_conn->local_mac[5];
+		((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
+		ucval = p_conn->local_mac[4];
+		((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
+
+		ucval = p_conn->remote_mac[1];
+		((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
+		ucval = p_conn->remote_mac[0];
+		((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
+		ucval = p_conn->remote_mac[3];
+		((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
+		ucval = p_conn->remote_mac[2];
+		((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
+		ucval = p_conn->remote_mac[5];
+		((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
+		ucval = p_conn->remote_mac[4];
+		((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
+
+		p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);
+		p_tcp2->flags = p_conn->tcp_flags;
+
+		p_tcp2->ip_version = p_conn->ip_version;
+		for (i = 0; i < 4; i++) {
+			dval = p_conn->remote_ip[i];
+			p_tcp2->remote_ip[i] = cpu_to_le32(dval);
+			dval = p_conn->local_ip[i];
+			p_tcp2->local_ip[i] = cpu_to_le32(dval);
+		}
+
+		p_tcp2->flow_label = cpu_to_le32(p_conn->flow_label);
+		p_tcp2->ttl = p_conn->ttl;
+		p_tcp2->tos_or_tc = p_conn->tos_or_tc;
+		p_tcp2->remote_port = cpu_to_le16(p_conn->remote_port);
+		p_tcp2->local_port = cpu_to_le16(p_conn->local_port);
+		p_tcp2->mss = cpu_to_le16(p_conn->mss);
+		p_tcp2->rcv_wnd_scale = p_conn->rcv_wnd_scale;
+		p_tcp2->connect_mode = p_conn->connect_mode;
+		wval = p_conn->syn_ip_payload_length;
+		p_tcp2->syn_ip_payload_length = cpu_to_le16(wval);
+		p_tcp2->syn_phy_addr_lo = DMA_LO_LE(p_conn->syn_phy_addr);
+		p_tcp2->syn_phy_addr_hi = DMA_HI_LE(p_conn->syn_phy_addr);
+	}
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
+				    struct qed_iscsi_conn *p_conn,
+				    enum spq_mode comp_mode,
+				    struct qed_spq_comp_cb *p_comp_addr)
+{
+	struct iscsi_conn_update_ramrod_params *p_ramrod = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	int rc = -EINVAL;
+	u32 dval;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = p_conn->icid;
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_conn_update;
+	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_UPDATE_CONN;
+	SET_FIELD(p_ramrod->hdr.flags,
+		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
+
+	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
+	p_ramrod->flags = p_conn->update_flag;
+	p_ramrod->max_seq_size = cpu_to_le32(p_conn->max_seq_size);
+	dval = p_conn->max_recv_pdu_length;
+	p_ramrod->max_recv_pdu_length = cpu_to_le32(dval);
+	dval = p_conn->max_send_pdu_length;
+	p_ramrod->max_send_pdu_length = cpu_to_le32(dval);
+	dval = p_conn->first_seq_length;
+	p_ramrod->first_seq_length = cpu_to_le32(dval);
+	p_ramrod->exp_stat_sn = cpu_to_le32(p_conn->exp_stat_sn);
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn,
+				       struct qed_iscsi_conn *p_conn,
+				       enum spq_mode comp_mode,
+				       struct qed_spq_comp_cb *p_comp_addr)
+{
+	struct iscsi_spe_conn_termination *p_ramrod = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	int rc = -EINVAL;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = p_conn->icid;
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_TERMINATION_CONN,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_conn_terminate;
+	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_TERMINATION_CONN;
+	SET_FIELD(p_ramrod->hdr.flags,
+		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
+
+	p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+	p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
+	p_ramrod->abortive = p_conn->abortive_dsconnect;
+
+	DMA_REGPAIR_LE(p_ramrod->query_params_addr,
+		       p_conn->tcp_upload_params_phys_addr);
+	DMA_REGPAIR_LE(p_ramrod->queue_cnts_addr, p_conn->queue_cnts_phys_addr);
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_iscsi_conn_clear_sq(struct qed_hwfn *p_hwfn,
+				      struct qed_iscsi_conn *p_conn,
+				      enum spq_mode comp_mode,
+				      struct qed_spq_comp_cb *p_comp_addr)
+{
+	struct iscsi_slow_path_hdr *p_ramrod = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	int rc = -EINVAL;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = p_conn->icid;
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_CLEAR_SQ,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_empty;
+	p_ramrod->op_code = ISCSI_RAMROD_CMD_ID_CLEAR_SQ;
+	SET_FIELD(p_ramrod->flags,
+		  ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_iscsi_func_stop(struct qed_hwfn *p_hwfn,
+				  enum spq_mode comp_mode,
+				  struct qed_spq_comp_cb *p_comp_addr)
+{
+	struct iscsi_spe_func_dstry *p_ramrod = NULL;
+	struct qed_spq_entry *p_ent = NULL;
+	struct qed_sp_init_data init_data;
+	int rc = 0;
+
+	/* Get SPQ entry */
+	memset(&init_data, 0, sizeof(init_data));
+	init_data.cid = qed_spq_get_cid(p_hwfn);
+	init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+	init_data.comp_mode = comp_mode;
+	init_data.p_comp_data = p_comp_addr;
+
+	rc = qed_sp_init_request(p_hwfn, &p_ent,
+				 ISCSI_RAMROD_CMD_ID_DESTROY_FUNC,
+				 PROTOCOLID_ISCSI, &init_data);
+	if (rc)
+		return rc;
+
+	p_ramrod = &p_ent->ramrod.iscsi_destroy;
+	p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_DESTROY_FUNC;
+
+	return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
+{
+	return (u8 __iomem *)p_hwfn->doorbells +
+			     qed_db_addr(cid, DQ_DEMS_LEGACY);
+}
+
+static void __iomem *qed_iscsi_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
+						    u8 bdq_id)
+{
+	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
+
+	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
+			     MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
+							     bdq_id);
+}
+
+static void __iomem *qed_iscsi_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
+						      u8 bdq_id)
+{
+	u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
+
+	return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
+			     TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
+							     bdq_id);
+}
+
+static int qed_iscsi_setup_connection(struct qed_hwfn *p_hwfn,
+				      struct qed_iscsi_conn *p_conn)
+{
+	if (!p_conn->queue_cnts_virt_addr)
+		goto nomem;
+	memset(p_conn->queue_cnts_virt_addr, 0,
+	       sizeof(*p_conn->queue_cnts_virt_addr));
+
+	if (!p_conn->tcp_upload_params_virt_addr)
+		goto nomem;
+	memset(p_conn->tcp_upload_params_virt_addr, 0,
+	       sizeof(*p_conn->tcp_upload_params_virt_addr));
+
+	if (!p_conn->r2tq.p_virt_addr)
+		goto nomem;
+	qed_chain_pbl_zero_mem(&p_conn->r2tq);
+
+	if (!p_conn->uhq.p_virt_addr)
+		goto nomem;
+	qed_chain_pbl_zero_mem(&p_conn->uhq);
+
+	if (!p_conn->xhq.p_virt_addr)
+		goto nomem;
+	qed_chain_pbl_zero_mem(&p_conn->xhq);
+
+	return 0;
+nomem:
+	return -ENOMEM;
+}
+
+static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn,
+					 struct qed_iscsi_conn **p_out_conn)
+{
+	u16 uhq_num_elements = 0, xhq_num_elements = 0, r2tq_num_elements = 0;
+	struct scsi_terminate_extra_params *p_q_cnts = NULL;
+	struct qed_iscsi_pf_params *p_params = NULL;
+	struct tcp_upload_params *p_tcp = NULL;
+	struct qed_iscsi_conn *p_conn = NULL;
+	int rc = 0;
+
+	/* Try finding a free connection that can be used */
+	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
+	if (!list_empty(&p_hwfn->p_iscsi_info->free_list))
+		p_conn = list_first_entry(&p_hwfn->p_iscsi_info->free_list,
+					  struct qed_iscsi_conn, list_entry);
+	if (p_conn) {
+		list_del(&p_conn->list_entry);
+		spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
+		*p_out_conn = p_conn;
+		return 0;
+	}
+	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
+
+	/* Need to allocate a new connection */
+	p_params = &p_hwfn->pf_params.iscsi_pf_params;
+
+	p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL);
+	if (!p_conn)
+		return -ENOMEM;
+
+	p_q_cnts = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
+				      sizeof(*p_q_cnts),
+				      &p_conn->queue_cnts_phys_addr,
+				      GFP_KERNEL);
+	if (!p_q_cnts)
+		goto nomem_queue_cnts_param;
+	p_conn->queue_cnts_virt_addr = p_q_cnts;
+
+	p_tcp = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
+				   sizeof(*p_tcp),
+				   &p_conn->tcp_upload_params_phys_addr,
+				   GFP_KERNEL);
+	if (!p_tcp)
+		goto nomem_upload_param;
+	p_conn->tcp_upload_params_virt_addr = p_tcp;
+
+	r2tq_num_elements = p_params->num_r2tq_pages_in_ring *
+			    QED_CHAIN_PAGE_SIZE / 0x80;
+	rc = qed_chain_alloc(p_hwfn->cdev,
+			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
+			     QED_CHAIN_MODE_PBL,
+			     QED_CHAIN_CNT_TYPE_U16,
+			     r2tq_num_elements, 0x80, &p_conn->r2tq);
+	if (rc)
+		goto nomem_r2tq;
+
+	uhq_num_elements = p_params->num_uhq_pages_in_ring *
+			   QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_uhqe);
+	rc = qed_chain_alloc(p_hwfn->cdev,
+			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
+			     QED_CHAIN_MODE_PBL,
+			     QED_CHAIN_CNT_TYPE_U16,
+			     uhq_num_elements,
+			     sizeof(struct iscsi_uhqe), &p_conn->uhq);
+	if (rc)
+		goto nomem_uhq;
+
+	xhq_num_elements = uhq_num_elements;
+	rc = qed_chain_alloc(p_hwfn->cdev,
+			     QED_CHAIN_USE_TO_CONSUME_PRODUCE,
+			     QED_CHAIN_MODE_PBL,
+			     QED_CHAIN_CNT_TYPE_U16,
+			     xhq_num_elements,
+			     sizeof(struct iscsi_xhqe), &p_conn->xhq);
+	if (rc)
+		goto nomem;
+
+	p_conn->free_on_delete = true;
+	*p_out_conn = p_conn;
+	return 0;
+
+nomem:
+	qed_chain_free(p_hwfn->cdev, &p_conn->uhq);
+nomem_uhq:
+	qed_chain_free(p_hwfn->cdev, &p_conn->r2tq);
+nomem_r2tq:
+	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+			  sizeof(struct tcp_upload_params),
+			  p_conn->tcp_upload_params_virt_addr,
+			  p_conn->tcp_upload_params_phys_addr);
+nomem_upload_param:
+	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+			  sizeof(struct scsi_terminate_extra_params),
+			  p_conn->queue_cnts_virt_addr,
+			  p_conn->queue_cnts_phys_addr);
+nomem_queue_cnts_param:
+	kfree(p_conn);
+
+	return -ENOMEM;
+}
+
+static int qed_iscsi_acquire_connection(struct qed_hwfn *p_hwfn,
+					struct qed_iscsi_conn *p_in_conn,
+					struct qed_iscsi_conn **p_out_conn)
+{
+	struct qed_iscsi_conn *p_conn = NULL;
+	int rc = 0;
+	u32 icid;
+
+	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
+	rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ISCSI, &icid);
+	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
+	if (rc)
+		return rc;
+
+	/* Use input connection or allocate a new one */
+	if (p_in_conn)
+		p_conn = p_in_conn;
+	else
+		rc = qed_iscsi_allocate_connection(p_hwfn, &p_conn);
+
+	if (!rc)
+		rc = qed_iscsi_setup_connection(p_hwfn, p_conn);
+
+	if (rc) {
+		spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
+		qed_cxt_release_cid(p_hwfn, icid);
+		spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
+		return rc;
+	}
+
+	p_conn->icid = icid;
+	p_conn->conn_id = (u16)icid;
+	p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid;
+
+	*p_out_conn = p_conn;
+
+	return rc;
+}
+
+static void qed_iscsi_release_connection(struct qed_hwfn *p_hwfn,
+					 struct qed_iscsi_conn *p_conn)
+{
+	spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
+	list_add_tail(&p_conn->list_entry, &p_hwfn->p_iscsi_info->free_list);
+	qed_cxt_release_cid(p_hwfn, p_conn->icid);
+	spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
+}
+
+struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn)
+{
+	struct qed_iscsi_info *p_iscsi_info;
+
+	p_iscsi_info = kzalloc(sizeof(*p_iscsi_info), GFP_KERNEL);
+	if (!p_iscsi_info) {
+		DP_NOTICE(p_hwfn, "Failed to allocate qed_iscsi_info'\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&p_iscsi_info->free_list);
+	return p_iscsi_info;
+}
+
+void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
+		     struct qed_iscsi_info *p_iscsi_info)
+{
+	spin_lock_init(&p_iscsi_info->lock);
+}
+
+void qed_iscsi_free(struct qed_hwfn *p_hwfn,
+		    struct qed_iscsi_info *p_iscsi_info)
+{
+	kfree(p_iscsi_info);
+}
+
+static void _qed_iscsi_get_tstats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct tstorm_iscsi_stats_drv tstats;
+	u32 tstats_addr;
+
+	memset(&tstats, 0, sizeof(tstats));
+	tstats_addr = BAR0_MAP_REG_TSDM_RAM +
+		      TSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats));
+
+	p_stats->iscsi_rx_bytes_cnt =
+	    HILO_64_REGPAIR(tstats.iscsi_rx_bytes_cnt);
+	p_stats->iscsi_rx_packet_cnt =
+	    HILO_64_REGPAIR(tstats.iscsi_rx_packet_cnt);
+	p_stats->iscsi_cmdq_threshold_cnt =
+	    le32_to_cpu(tstats.iscsi_cmdq_threshold_cnt);
+	p_stats->iscsi_rq_threshold_cnt =
+	    le32_to_cpu(tstats.iscsi_rq_threshold_cnt);
+	p_stats->iscsi_immq_threshold_cnt =
+	    le32_to_cpu(tstats.iscsi_immq_threshold_cnt);
+}
+
+static void _qed_iscsi_get_mstats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct mstorm_iscsi_stats_drv mstats;
+	u32 mstats_addr;
+
+	memset(&mstats, 0, sizeof(mstats));
+	mstats_addr = BAR0_MAP_REG_MSDM_RAM +
+		      MSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &mstats, mstats_addr, sizeof(mstats));
+
+	p_stats->iscsi_rx_dropped_pdus_task_not_valid =
+	    HILO_64_REGPAIR(mstats.iscsi_rx_dropped_pdus_task_not_valid);
+}
+
+static void _qed_iscsi_get_ustats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct ustorm_iscsi_stats_drv ustats;
+	u32 ustats_addr;
+
+	memset(&ustats, 0, sizeof(ustats));
+	ustats_addr = BAR0_MAP_REG_USDM_RAM +
+		      USTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &ustats, ustats_addr, sizeof(ustats));
+
+	p_stats->iscsi_rx_data_pdu_cnt =
+	    HILO_64_REGPAIR(ustats.iscsi_rx_data_pdu_cnt);
+	p_stats->iscsi_rx_r2t_pdu_cnt =
+	    HILO_64_REGPAIR(ustats.iscsi_rx_r2t_pdu_cnt);
+	p_stats->iscsi_rx_total_pdu_cnt =
+	    HILO_64_REGPAIR(ustats.iscsi_rx_total_pdu_cnt);
+}
+
+static void _qed_iscsi_get_xstats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct xstorm_iscsi_stats_drv xstats;
+	u32 xstats_addr;
+
+	memset(&xstats, 0, sizeof(xstats));
+	xstats_addr = BAR0_MAP_REG_XSDM_RAM +
+		      XSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &xstats, xstats_addr, sizeof(xstats));
+
+	p_stats->iscsi_tx_go_to_slow_start_event_cnt =
+	    HILO_64_REGPAIR(xstats.iscsi_tx_go_to_slow_start_event_cnt);
+	p_stats->iscsi_tx_fast_retransmit_event_cnt =
+	    HILO_64_REGPAIR(xstats.iscsi_tx_fast_retransmit_event_cnt);
+}
+
+static void _qed_iscsi_get_ystats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct ystorm_iscsi_stats_drv ystats;
+	u32 ystats_addr;
+
+	memset(&ystats, 0, sizeof(ystats));
+	ystats_addr = BAR0_MAP_REG_YSDM_RAM +
+		      YSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &ystats, ystats_addr, sizeof(ystats));
+
+	p_stats->iscsi_tx_data_pdu_cnt =
+	    HILO_64_REGPAIR(ystats.iscsi_tx_data_pdu_cnt);
+	p_stats->iscsi_tx_r2t_pdu_cnt =
+	    HILO_64_REGPAIR(ystats.iscsi_tx_r2t_pdu_cnt);
+	p_stats->iscsi_tx_total_pdu_cnt =
+	    HILO_64_REGPAIR(ystats.iscsi_tx_total_pdu_cnt);
+}
+
+static void _qed_iscsi_get_pstats(struct qed_hwfn *p_hwfn,
+				  struct qed_ptt *p_ptt,
+				  struct qed_iscsi_stats *p_stats)
+{
+	struct pstorm_iscsi_stats_drv pstats;
+	u32 pstats_addr;
+
+	memset(&pstats, 0, sizeof(pstats));
+	pstats_addr = BAR0_MAP_REG_PSDM_RAM +
+		      PSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
+	qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats));
+
+	p_stats->iscsi_tx_bytes_cnt =
+	    HILO_64_REGPAIR(pstats.iscsi_tx_bytes_cnt);
+	p_stats->iscsi_tx_packet_cnt =
+	    HILO_64_REGPAIR(pstats.iscsi_tx_packet_cnt);
+}
+
+static int qed_iscsi_get_stats(struct qed_hwfn *p_hwfn,
+			       struct qed_iscsi_stats *stats)
+{
+	struct qed_ptt *p_ptt;
+
+	memset(stats, 0, sizeof(*stats));
+
+	p_ptt = qed_ptt_acquire(p_hwfn);
+	if (!p_ptt) {
+		DP_ERR(p_hwfn, "Failed to acquire ptt\n");
+		return -EAGAIN;
+	}
+
+	_qed_iscsi_get_tstats(p_hwfn, p_ptt, stats);
+	_qed_iscsi_get_mstats(p_hwfn, p_ptt, stats);
+	_qed_iscsi_get_ustats(p_hwfn, p_ptt, stats);
+
+	_qed_iscsi_get_xstats(p_hwfn, p_ptt, stats);
+	_qed_iscsi_get_ystats(p_hwfn, p_ptt, stats);
+	_qed_iscsi_get_pstats(p_hwfn, p_ptt, stats);
+
+	qed_ptt_release(p_hwfn, p_ptt);
+
+	return 0;
+}
+
+struct qed_hash_iscsi_con {
+	struct hlist_node node;
+	struct qed_iscsi_conn *con;
+};
+
+static int qed_fill_iscsi_dev_info(struct qed_dev *cdev,
+				   struct qed_dev_iscsi_info *info)
+{
+	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+
+	int rc;
+
+	memset(info, 0, sizeof(*info));
+	rc = qed_fill_dev_info(cdev, &info->common);
+
+	info->primary_dbq_rq_addr =
+	    qed_iscsi_get_primary_bdq_prod(hwfn, BDQ_ID_RQ);
+	info->secondary_bdq_rq_addr =
+	    qed_iscsi_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ);
+
+	return rc;
+}
+
+static void qed_register_iscsi_ops(struct qed_dev *cdev,
+				   struct qed_iscsi_cb_ops *ops, void *cookie)
+{
+	cdev->protocol_ops.iscsi = ops;
+	cdev->ops_cookie = cookie;
+}
+
+static struct qed_hash_iscsi_con *qed_iscsi_get_hash(struct qed_dev *cdev,
+						     u32 handle)
+{
+	struct qed_hash_iscsi_con *hash_con = NULL;
+
+	if (!(cdev->flags & QED_FLAG_STORAGE_STARTED))
+		return NULL;
+
+	hash_for_each_possible(cdev->connections, hash_con, node, handle) {
+		if (hash_con->con->icid == handle)
+			break;
+	}
+
+	if (!hash_con || (hash_con->con->icid != handle))
+		return NULL;
+
+	return hash_con;
+}
+
+static int qed_iscsi_stop(struct qed_dev *cdev)
+{
+	int rc;
+
+	if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) {
+		DP_NOTICE(cdev, "iscsi already stopped\n");
+		return 0;
+	}
+
+	if (!hash_empty(cdev->connections)) {
+		DP_NOTICE(cdev,
+			  "Can't stop iscsi - not all connections were returned\n");
+		return -EINVAL;
+	}
+
+	/* Stop the iscsi */
+	rc = qed_sp_iscsi_func_stop(QED_LEADING_HWFN(cdev),
+				    QED_SPQ_MODE_EBLOCK, NULL);
+	cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
+
+	return rc;
+}
+
+static int qed_iscsi_start(struct qed_dev *cdev,
+			   struct qed_iscsi_tid *tasks,
+			   void *event_context,
+			   iscsi_event_cb_t async_event_cb)
+{
+	int rc;
+
+	if (cdev->flags & QED_FLAG_STORAGE_STARTED) {
+		DP_NOTICE(cdev, "iscsi already started;\n");
+		return 0;
+	}
+
+	rc = qed_sp_iscsi_func_start(QED_LEADING_HWFN(cdev),
+				     QED_SPQ_MODE_EBLOCK, NULL, event_context,
+				     async_event_cb);
+	if (rc) {
+		DP_NOTICE(cdev, "Failed to start iscsi\n");
+		return rc;
+	}
+
+	cdev->flags |= QED_FLAG_STORAGE_STARTED;
+	hash_init(cdev->connections);
+
+	if (tasks) {
+		struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
+						       GFP_KERNEL);
+
+		if (!tid_info) {
+			DP_NOTICE(cdev,
+				  "Failed to allocate tasks information\n");
+			qed_iscsi_stop(cdev);
+			return -ENOMEM;
+		}
+
+		rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
+					      tid_info);
+		if (rc) {
+			DP_NOTICE(cdev, "Failed to gather task information\n");
+			qed_iscsi_stop(cdev);
+			kfree(tid_info);
+			return rc;
+		}
+
+		/* Fill task information */
+		tasks->size = tid_info->tid_size;
+		tasks->num_tids_per_block = tid_info->num_tids_per_block;
+		memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
+
+		kfree(tid_info);
+	}
+
+	return 0;
+}
+
+static int qed_iscsi_acquire_conn(struct qed_dev *cdev,
+				  u32 *handle,
+				  u32 *fw_cid, void __iomem **p_doorbell)
+{
+	struct qed_hash_iscsi_con *hash_con;
+	int rc;
+
+	/* Allocate a hashed connection */
+	hash_con = kzalloc(sizeof(*hash_con), GFP_ATOMIC);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to allocate hashed connection\n");
+		return -ENOMEM;
+	}
+
+	/* Acquire the connection */
+	rc = qed_iscsi_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
+					  &hash_con->con);
+	if (rc) {
+		DP_NOTICE(cdev, "Failed to acquire Connection\n");
+		kfree(hash_con);
+		return rc;
+	}
+
+	/* Added the connection to hash table */
+	*handle = hash_con->con->icid;
+	*fw_cid = hash_con->con->fw_cid;
+	hash_add(cdev->connections, &hash_con->node, *handle);
+
+	if (p_doorbell)
+		*p_doorbell = qed_iscsi_get_db_addr(QED_LEADING_HWFN(cdev),
+						    *handle);
+
+	return 0;
+}
+
+static int qed_iscsi_release_conn(struct qed_dev *cdev, u32 handle)
+{
+	struct qed_hash_iscsi_con *hash_con;
+
+	hash_con = qed_iscsi_get_hash(cdev, handle);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+			  handle);
+		return -EINVAL;
+	}
+
+	hlist_del(&hash_con->node);
+	qed_iscsi_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
+	kfree(hash_con);
+
+	return 0;
+}
+
+static int qed_iscsi_offload_conn(struct qed_dev *cdev,
+				  u32 handle,
+				  struct qed_iscsi_params_offload *conn_info)
+{
+	struct qed_hash_iscsi_con *hash_con;
+	struct qed_iscsi_conn *con;
+
+	hash_con = qed_iscsi_get_hash(cdev, handle);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+			  handle);
+		return -EINVAL;
+	}
+
+	/* Update the connection with information from the params */
+	con = hash_con->con;
+
+	ether_addr_copy(con->local_mac, conn_info->src.mac);
+	ether_addr_copy(con->remote_mac, conn_info->dst.mac);
+	memcpy(con->local_ip, conn_info->src.ip, sizeof(con->local_ip));
+	memcpy(con->remote_ip, conn_info->dst.ip, sizeof(con->remote_ip));
+	con->local_port = conn_info->src.port;
+	con->remote_port = conn_info->dst.port;
+
+	con->layer_code = conn_info->layer_code;
+	con->sq_pbl_addr = conn_info->sq_pbl_addr;
+	con->initial_ack = conn_info->initial_ack;
+	con->vlan_id = conn_info->vlan_id;
+	con->tcp_flags = conn_info->tcp_flags;
+	con->ip_version = conn_info->ip_version;
+	con->default_cq = conn_info->default_cq;
+	con->ka_max_probe_cnt = conn_info->ka_max_probe_cnt;
+	con->dup_ack_theshold = conn_info->dup_ack_theshold;
+	con->rcv_next = conn_info->rcv_next;
+	con->snd_una = conn_info->snd_una;
+	con->snd_next = conn_info->snd_next;
+	con->snd_max = conn_info->snd_max;
+	con->snd_wnd = conn_info->snd_wnd;
+	con->rcv_wnd = conn_info->rcv_wnd;
+	con->snd_wl1 = conn_info->snd_wl1;
+	con->cwnd = conn_info->cwnd;
+	con->ss_thresh = conn_info->ss_thresh;
+	con->srtt = conn_info->srtt;
+	con->rtt_var = conn_info->rtt_var;
+	con->ts_time = conn_info->ts_time;
+	con->ts_recent = conn_info->ts_recent;
+	con->ts_recent_age = conn_info->ts_recent_age;
+	con->total_rt = conn_info->total_rt;
+	con->ka_timeout_delta = conn_info->ka_timeout_delta;
+	con->rt_timeout_delta = conn_info->rt_timeout_delta;
+	con->dup_ack_cnt = conn_info->dup_ack_cnt;
+	con->snd_wnd_probe_cnt = conn_info->snd_wnd_probe_cnt;
+	con->ka_probe_cnt = conn_info->ka_probe_cnt;
+	con->rt_cnt = conn_info->rt_cnt;
+	con->flow_label = conn_info->flow_label;
+	con->ka_timeout = conn_info->ka_timeout;
+	con->ka_interval = conn_info->ka_interval;
+	con->max_rt_time = conn_info->max_rt_time;
+	con->initial_rcv_wnd = conn_info->initial_rcv_wnd;
+	con->ttl = conn_info->ttl;
+	con->tos_or_tc = conn_info->tos_or_tc;
+	con->remote_port = conn_info->remote_port;
+	con->local_port = conn_info->local_port;
+	con->mss = conn_info->mss;
+	con->snd_wnd_scale = conn_info->snd_wnd_scale;
+	con->rcv_wnd_scale = conn_info->rcv_wnd_scale;
+	con->ts_ticks_per_second = conn_info->ts_ticks_per_second;
+	con->da_timeout_value = conn_info->da_timeout_value;
+	con->ack_frequency = conn_info->ack_frequency;
+
+	/* Set default values on other connection fields */
+	con->offl_flags = 0x1;
+
+	return qed_sp_iscsi_conn_offload(QED_LEADING_HWFN(cdev), con,
+					 QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_iscsi_update_conn(struct qed_dev *cdev,
+				 u32 handle,
+				 struct qed_iscsi_params_update *conn_info)
+{
+	struct qed_hash_iscsi_con *hash_con;
+	struct qed_iscsi_conn *con;
+
+	hash_con = qed_iscsi_get_hash(cdev, handle);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+			  handle);
+		return -EINVAL;
+	}
+
+	/* Update the connection with information from the params */
+	con = hash_con->con;
+	con->update_flag = conn_info->update_flag;
+	con->max_seq_size = conn_info->max_seq_size;
+	con->max_recv_pdu_length = conn_info->max_recv_pdu_length;
+	con->max_send_pdu_length = conn_info->max_send_pdu_length;
+	con->first_seq_length = conn_info->first_seq_length;
+	con->exp_stat_sn = conn_info->exp_stat_sn;
+
+	return qed_sp_iscsi_conn_update(QED_LEADING_HWFN(cdev), con,
+					QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_iscsi_clear_conn_sq(struct qed_dev *cdev, u32 handle)
+{
+	struct qed_hash_iscsi_con *hash_con;
+
+	hash_con = qed_iscsi_get_hash(cdev, handle);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+			  handle);
+		return -EINVAL;
+	}
+
+	return qed_sp_iscsi_conn_clear_sq(QED_LEADING_HWFN(cdev),
+					  hash_con->con,
+					  QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_iscsi_destroy_conn(struct qed_dev *cdev,
+				  u32 handle, u8 abrt_conn)
+{
+	struct qed_hash_iscsi_con *hash_con;
+
+	hash_con = qed_iscsi_get_hash(cdev, handle);
+	if (!hash_con) {
+		DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+			  handle);
+		return -EINVAL;
+	}
+
+	hash_con->con->abortive_dsconnect = abrt_conn;
+
+	return qed_sp_iscsi_conn_terminate(QED_LEADING_HWFN(cdev),
+					   hash_con->con,
+					   QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats)
+{
+	return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats);
+}
+
+static const struct qed_iscsi_ops qed_iscsi_ops_pass = {
+	.common = &qed_common_ops_pass,
+	.ll2 = &qed_ll2_ops_pass,
+	.fill_dev_info = &qed_fill_iscsi_dev_info,
+	.register_ops = &qed_register_iscsi_ops,
+	.start = &qed_iscsi_start,
+	.stop = &qed_iscsi_stop,
+	.acquire_conn = &qed_iscsi_acquire_conn,
+	.release_conn = &qed_iscsi_release_conn,
+	.offload_conn = &qed_iscsi_offload_conn,
+	.update_conn = &qed_iscsi_update_conn,
+	.destroy_conn = &qed_iscsi_destroy_conn,
+	.clear_sq = &qed_iscsi_clear_conn_sq,
+	.get_stats = &qed_iscsi_stats,
+};
+
+const struct qed_iscsi_ops *qed_get_iscsi_ops()
+{
+	return &qed_iscsi_ops_pass;
+}
+EXPORT_SYMBOL(qed_get_iscsi_ops);
+
+void qed_put_iscsi_ops(void)
+{
+}
+EXPORT_SYMBOL(qed_put_iscsi_ops);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
new file mode 100644
index 0000000..269848c
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
@@ -0,0 +1,52 @@ 
+/* QLogic qed NIC Driver
+ * Copyright (c) 2015 QLogic Corporation
+ *
+ * This software is available 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.
+ */
+
+#ifndef _QED_ISCSI_H
+#define _QED_ISCSI_H
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/qed/tcp_common.h>
+#include <linux/qed/qed_iscsi_if.h>
+#include <linux/qed/qed_chain.h>
+#include "qed.h"
+#include "qed_hsi.h"
+#include "qed_mcp.h"
+#include "qed_sp.h"
+
+struct qed_iscsi_info {
+	spinlock_t lock;
+	struct list_head free_list;
+	u16 max_num_outstanding_tasks;
+	void *event_context;
+	iscsi_event_cb_t event_cb;
+};
+
+#ifdef CONFIG_QED_LL2
+extern const struct qed_ll2_ops qed_ll2_ops_pass;
+#endif
+
+#if IS_ENABLED(CONFIG_QEDI)
+struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn);
+
+void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
+		     struct qed_iscsi_info *p_iscsi_info);
+
+void qed_iscsi_free(struct qed_hwfn *p_hwfn,
+		    struct qed_iscsi_info *p_iscsi_info);
+#else /* IS_ENABLED(CONFIG_QEDI) */
+static inline struct qed_iscsi_info *qed_iscsi_alloc(
+		struct qed_hwfn *p_hwfn) { return NULL; }
+static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
+		struct qed_iscsi_info *p_iscsi_info) {}
+static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn,
+		struct qed_iscsi_info *p_iscsi_info) {}
+#endif /* IS_ENABLED(CONFIG_QEDI) */
+
+#endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
index ddd410a..07e2f77 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -2187,6 +2187,5 @@  const struct qed_eth_ops *qed_get_eth_ops(void)
 
 void qed_put_eth_ops(void)
 {
-	/* TODO - reference count for module? */
 }
 EXPORT_SYMBOL(qed_put_eth_ops);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index a6db107..e67f3c9 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -299,6 +299,7 @@  static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
 		p_tx->cur_completing_bd_idx = 1;
 		b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
 		tx_frag = p_pkt->bds_set[0].tx_frag;
+#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 		if (p_ll2_conn->gsi_enable)
 			qed_ll2b_release_tx_gsi_packet(p_hwfn,
 						       p_ll2_conn->my_id,
@@ -307,6 +308,7 @@  static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
 						       b_last_frag,
 						       b_last_packet);
 		else
+#endif
 			qed_ll2b_complete_tx_packet(p_hwfn,
 						    p_ll2_conn->my_id,
 						    p_pkt->cookie,
@@ -367,6 +369,7 @@  static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
 
 		spin_unlock_irqrestore(&p_tx->lock, flags);
 		tx_frag = p_pkt->bds_set[0].tx_frag;
+#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 		if (p_ll2_conn->gsi_enable)
 			qed_ll2b_complete_tx_gsi_packet(p_hwfn,
 							p_ll2_conn->my_id,
@@ -374,6 +377,7 @@  static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
 							tx_frag,
 							b_last_frag, !num_bds);
 		else
+#endif
 			qed_ll2b_complete_tx_packet(p_hwfn,
 						    p_ll2_conn->my_id,
 						    p_pkt->cookie,
@@ -421,6 +425,7 @@  static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
 			  "Mismatch between active_descq and the LL2 Rx chain\n");
 	list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
 
+#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 	spin_unlock_irqrestore(&p_rx->lock, lock_flags);
 	qed_ll2b_complete_rx_gsi_packet(p_hwfn,
 					p_ll2_info->my_id,
@@ -433,6 +438,7 @@  static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
 					src_mac_addrhi,
 					src_mac_addrlo, b_last_cqe);
 	spin_lock_irqsave(&p_rx->lock, lock_flags);
+#endif
 
 	return 0;
 }
@@ -1516,11 +1522,12 @@  static void qed_ll2_register_cb_ops(struct qed_dev *cdev,
 
 static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
 {
-	struct qed_ll2_info ll2_info;
+	struct qed_ll2_info *ll2_info;
 	struct qed_ll2_buffer *buffer;
 	enum qed_ll2_conn_type conn_type;
 	struct qed_ptt *p_ptt;
 	int rc, i;
+	u8 gsi_enable = 1;
 
 	/* Initialize LL2 locks & lists */
 	INIT_LIST_HEAD(&cdev->ll2->list);
@@ -1552,6 +1559,7 @@  static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
 	switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
 	case QED_PCI_ISCSI:
 		conn_type = QED_LL2_TYPE_ISCSI;
+		gsi_enable = 0;
 		break;
 	case QED_PCI_ETH_ROCE:
 		conn_type = QED_LL2_TYPE_ROCE;
@@ -1561,18 +1569,23 @@  static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
 	}
 
 	/* Prepare the temporary ll2 information */
-	memset(&ll2_info, 0, sizeof(ll2_info));
-	ll2_info.conn_type = conn_type;
-	ll2_info.mtu = params->mtu;
-	ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
-	ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
-	ll2_info.tx_tc = 0;
-	ll2_info.tx_dest = CORE_TX_DEST_NW;
-	ll2_info.gsi_enable = 1;
-
-	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
+	ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
+	if (!ll2_info) {
+		DP_INFO(cdev, "Failed to allocate LL2 info buffer\n");
+		goto fail;
+	}
+	ll2_info->conn_type = conn_type;
+	ll2_info->mtu = params->mtu;
+	ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
+	ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
+	ll2_info->tx_tc = 0;
+	ll2_info->tx_dest = CORE_TX_DEST_NW;
+	ll2_info->gsi_enable = gsi_enable;
+
+	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), ll2_info,
 					QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
 					&cdev->ll2->handle);
+	kfree(ll2_info);
 	if (rc) {
 		DP_INFO(cdev, "Failed to acquire LL2 connection\n");
 		goto fail;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 4ee3151..a01ad9d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -1239,7 +1239,6 @@  static void qed_fill_link(struct qed_hwfn *hwfn,
 	if (link.link_up)
 		if_link->link_up = true;
 
-	/* TODO - at the moment assume supported and advertised speed equal */
 	if_link->supported_caps = QED_LM_FIBRE_BIT;
 	if (params.speed.autoneg)
 		if_link->supported_caps |= QED_LM_Autoneg_BIT;
@@ -1294,7 +1293,6 @@  static void qed_fill_link(struct qed_hwfn *hwfn,
 	if (link.link_up)
 		if_link->speed = link.speed;
 
-	/* TODO - fill duplex properly */
 	if_link->duplex = DUPLEX_FULL;
 	qed_mcp_get_media_type(hwfn->cdev, &media_type);
 	if_link->port = qed_get_port_type(media_type);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
index dff520e..2e5f51b 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -314,9 +314,6 @@  int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
 
 /* Using hwfn number (and not pf_num) is required since in CMT mode,
  * same pf_num may be used by two different hwfn
- * TODO - this shouldn't really be in .h file, but until all fields
- * required during hw-init will be placed in their correct place in shmem
- * we need it in qed_dev.c [for readin the nvram reflection in shmem].
  */
 #define MCP_PF_ID_BY_REL(p_hwfn, rel_pfid) (QED_IS_BB((p_hwfn)->cdev) ?	       \
 					    ((rel_pfid) |		       \
@@ -324,9 +321,6 @@  int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
 					    rel_pfid)
 #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id)
 
-/* TODO - this is only correct as long as only BB is supported, and
- * no port-swapping is implemented; Afterwards we'll need to fix it.
- */
 #define MFW_PORT(_p_hwfn)       ((_p_hwfn)->abs_pf_id %	\
 				 ((_p_hwfn)->cdev->num_ports_in_engines * 2))
 struct qed_mcp_info {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
index b414a05..9754420 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
@@ -82,6 +82,8 @@ 
 	0x1c80000UL
 #define BAR0_MAP_REG_XSDM_RAM \
 	0x1e00000UL
+#define BAR0_MAP_REG_YSDM_RAM \
+	0x1e80000UL
 #define  NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
 	0x5011f4UL
 #define  PRS_REG_SEARCH_TCP \
diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
index caff415..d3fa578 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
@@ -24,6 +24,7 @@ 
 #include "qed_hsi.h"
 #include "qed_hw.h"
 #include "qed_int.h"
+#include "qed_iscsi.h"
 #include "qed_mcp.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
@@ -249,6 +250,20 @@  static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
 		return qed_sriov_eqe_event(p_hwfn,
 					   p_eqe->opcode,
 					   p_eqe->echo, &p_eqe->data);
+	case PROTOCOLID_ISCSI:
+		if (!IS_ENABLED(CONFIG_QEDI))
+			return -EINVAL;
+
+		if (p_hwfn->p_iscsi_info->event_cb) {
+			struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info;
+
+			return p_iscsi->event_cb(p_iscsi->event_context,
+						 p_eqe->opcode, &p_eqe->data);
+		} else {
+			DP_NOTICE(p_hwfn,
+				  "iSCSI async completion is not set\n");
+			return -EINVAL;
+		}
 	default:
 		DP_NOTICE(p_hwfn,
 			  "Unknown Async completion for protocol: %d\n",
diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
index f9ae903..c0c9fa8 100644
--- a/include/linux/qed/qed_if.h
+++ b/include/linux/qed/qed_if.h
@@ -165,6 +165,7 @@  struct qed_iscsi_pf_params {
 	u32 max_cwnd;
 	u16 cq_num_entries;
 	u16 cmdq_num_entries;
+	u32 two_msl_timer;
 	u16 dup_ack_threshold;
 	u16 tx_sws_timer;
 	u16 min_rto;
@@ -271,6 +272,7 @@  struct qed_dev_info {
 enum qed_sb_type {
 	QED_SB_TYPE_L2_QUEUE,
 	QED_SB_TYPE_CNQ,
+	QED_SB_TYPE_STORAGE,
 };
 
 enum qed_protocol {
diff --git a/include/linux/qed/qed_iscsi_if.h b/include/linux/qed/qed_iscsi_if.h
new file mode 100644
index 0000000..6735ee5
--- /dev/null
+++ b/include/linux/qed/qed_iscsi_if.h
@@ -0,0 +1,249 @@ 
+/* QLogic qed NIC Driver
+ * Copyright (c) 2015 QLogic Corporation
+ *
+ * This software is available 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.
+ */
+
+#ifndef _QED_ISCSI_IF_H
+#define _QED_ISCSI_IF_H
+#include <linux/types.h>
+#include <linux/qed/qed_if.h>
+
+typedef int (*iscsi_event_cb_t) (void *context,
+				 u8 fw_event_code, void *fw_handle);
+struct qed_iscsi_stats {
+	u64 iscsi_rx_bytes_cnt;
+	u64 iscsi_rx_packet_cnt;
+	u64 iscsi_rx_new_ooo_isle_events_cnt;
+	u32 iscsi_cmdq_threshold_cnt;
+	u32 iscsi_rq_threshold_cnt;
+	u32 iscsi_immq_threshold_cnt;
+
+	u64 iscsi_rx_dropped_pdus_task_not_valid;
+
+	u64 iscsi_rx_data_pdu_cnt;
+	u64 iscsi_rx_r2t_pdu_cnt;
+	u64 iscsi_rx_total_pdu_cnt;
+
+	u64 iscsi_tx_go_to_slow_start_event_cnt;
+	u64 iscsi_tx_fast_retransmit_event_cnt;
+
+	u64 iscsi_tx_data_pdu_cnt;
+	u64 iscsi_tx_r2t_pdu_cnt;
+	u64 iscsi_tx_total_pdu_cnt;
+
+	u64 iscsi_tx_bytes_cnt;
+	u64 iscsi_tx_packet_cnt;
+};
+
+struct qed_dev_iscsi_info {
+	struct qed_dev_info common;
+
+	void __iomem *primary_dbq_rq_addr;
+	void __iomem *secondary_bdq_rq_addr;
+};
+
+struct qed_iscsi_id_params {
+	u8 mac[ETH_ALEN];
+	u32 ip[4];
+	u16 port;
+};
+
+struct qed_iscsi_params_offload {
+	u8 layer_code;
+	dma_addr_t sq_pbl_addr;
+	u32 initial_ack;
+
+	struct qed_iscsi_id_params src;
+	struct qed_iscsi_id_params dst;
+	u16 vlan_id;
+	u8 tcp_flags;
+	u8 ip_version;
+	u8 default_cq;
+
+	u8 ka_max_probe_cnt;
+	u8 dup_ack_theshold;
+	u32 rcv_next;
+	u32 snd_una;
+	u32 snd_next;
+	u32 snd_max;
+	u32 snd_wnd;
+	u32 rcv_wnd;
+	u32 snd_wl1;
+	u32 cwnd;
+	u32 ss_thresh;
+	u16 srtt;
+	u16 rtt_var;
+	u32 ts_time;
+	u32 ts_recent;
+	u32 ts_recent_age;
+	u32 total_rt;
+	u32 ka_timeout_delta;
+	u32 rt_timeout_delta;
+	u8 dup_ack_cnt;
+	u8 snd_wnd_probe_cnt;
+	u8 ka_probe_cnt;
+	u8 rt_cnt;
+	u32 flow_label;
+	u32 ka_timeout;
+	u32 ka_interval;
+	u32 max_rt_time;
+	u32 initial_rcv_wnd;
+	u8 ttl;
+	u8 tos_or_tc;
+	u16 remote_port;
+	u16 local_port;
+	u16 mss;
+	u8 snd_wnd_scale;
+	u8 rcv_wnd_scale;
+	u32 ts_ticks_per_second;
+	u16 da_timeout_value;
+	u8 ack_frequency;
+};
+
+struct qed_iscsi_params_update {
+	u8 update_flag;
+#define QED_ISCSI_CONN_HD_EN            BIT(0)
+#define QED_ISCSI_CONN_DD_EN            BIT(1)
+#define QED_ISCSI_CONN_INITIAL_R2T      BIT(2)
+#define QED_ISCSI_CONN_IMMEDIATE_DATA   BIT(3)
+
+	u32 max_seq_size;
+	u32 max_recv_pdu_length;
+	u32 max_send_pdu_length;
+	u32 first_seq_length;
+	u32 exp_stat_sn;
+};
+
+#define MAX_TID_BLOCKS_ISCSI (512)
+struct qed_iscsi_tid {
+	u32 size;		/* In bytes per task */
+	u32 num_tids_per_block;
+	u8 *blocks[MAX_TID_BLOCKS_ISCSI];
+};
+
+struct qed_iscsi_cb_ops {
+	struct qed_common_cb_ops common;
+
+	/* TODO - need to add handler for ansync. events */
+};
+
+struct qed_iscsi_ops {
+	const struct qed_common_ops *common;
+
+	const struct qed_ll2_ops *ll2;
+
+	int (*fill_dev_info)(struct qed_dev *cdev,
+			     struct qed_dev_iscsi_info *info);
+
+	void (*register_ops)(struct qed_dev *cdev,
+			     struct qed_iscsi_cb_ops *ops, void *cookie);
+
+/**
+ * @brief start iscsi in FW
+ *
+ * @param cdev
+ * @param tasks - qed will fill information about tasks
+ *
+ * return 0 on success, otherwise error value.
+ */
+	int (*start)(struct qed_dev *cdev,
+		     struct qed_iscsi_tid *tasks,
+		     void *event_context, iscsi_event_cb_t async_event_cb);
+
+/**
+ * @brief stops iscsi in FW
+ *
+ * @param cdev
+ *
+ * return 0 on success, otherwise error value.
+ */
+	int (*stop)(struct qed_dev *cdev);
+
+/**
+ * @brief acquire_conn - acquire a new iscsi connection
+ *
+ * @param cdev
+ * @param handle - qed will fill handle that should be used
+ *                 henceforth as identifier of the connection.
+ * @param p_doorbell - qed will fill the address of the doorbell.
+ *
+ * @return 0 on sucesss, otherwise error value.
+ */
+	int (*acquire_conn)(struct qed_dev *cdev,
+			    u32 *handle,
+			    u32 *fw_cid, void __iomem **p_doorbell);
+
+/**
+ * @brief release_conn - release a previously acquired iscsi connection
+ *
+ * @param cdev
+ * @param handle - the connection handle.
+ *
+ * @return 0 on success, otherwise error value.
+ */
+	int (*release_conn)(struct qed_dev *cdev, u32 handle);
+
+/**
+ * @brief offload_conn - configures an offloaded connection
+ *
+ * @param cdev
+ * @param handle - the connection handle.
+ * @param conn_info - the configuration to use for the offload.
+ *
+ * @return 0 on success, otherwise error value.
+ */
+	int (*offload_conn)(struct qed_dev *cdev,
+			    u32 handle,
+			    struct qed_iscsi_params_offload *conn_info);
+
+/**
+ * @brief update_conn - updates an offloaded connection
+ *
+ * @param cdev
+ * @param handle - the connection handle.
+ * @param conn_info - the configuration to use for the offload.
+ *
+ * @return 0 on success, otherwise error value.
+ */
+	int (*update_conn)(struct qed_dev *cdev,
+			   u32 handle,
+			   struct qed_iscsi_params_update *conn_info);
+
+/**
+ * @brief destroy_conn - stops an offloaded connection
+ *
+ * @param cdev
+ * @param handle - the connection handle.
+ *
+ * @return 0 on success, otherwise error value.
+ */
+	int (*destroy_conn)(struct qed_dev *cdev, u32 handle, u8 abrt_conn);
+
+/**
+ * @brief clear_sq - clear all task in sq
+ *
+ * @param cdev
+ * @param handle - the connection handle.
+ *
+ * @return 0 on success, otherwise error value.
+ */
+	int (*clear_sq)(struct qed_dev *cdev, u32 handle);
+
+/**
+ * @brief get iSCSI related statistics
+ *
+ * @param cdev
+ * @param stats - pointer to struck that would be filled we stats
+ *
+ * @return 0 on success, error otherwise.
+ */
+	int (*get_stats)(struct qed_dev *cdev,
+			 struct qed_iscsi_stats *stats);
+};
+
+const struct qed_iscsi_ops *qed_get_iscsi_ops(void);
+void qed_put_iscsi_ops(void);
+#endif