162306a36Sopenharmony_ci/* bnx2i_hwi.c: QLogic NetXtreme II iSCSI driver.
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright (c) 2006 - 2013 Broadcom Corporation
462306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
562306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mike Christie
662306a36Sopenharmony_ci * Copyright (c) 2014, QLogic Corporation
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
962306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1062306a36Sopenharmony_ci * the Free Software Foundation.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
1362306a36Sopenharmony_ci * Previously Maintained by: Eddie Wai (eddie.wai@broadcom.com)
1462306a36Sopenharmony_ci * Maintained by: QLogic-Storage-Upstream@qlogic.com
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/gfp.h>
1862306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1962306a36Sopenharmony_ci#include <scsi/libiscsi.h>
2062306a36Sopenharmony_ci#include "bnx2i.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciDECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/**
2562306a36Sopenharmony_ci * bnx2i_get_cid_num - get cid from ep
2662306a36Sopenharmony_ci * @ep: 	endpoint pointer
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Only applicable to 57710 family of devices
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_cistatic u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	u32 cid;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
3562306a36Sopenharmony_ci		cid = ep->ep_cid;
3662306a36Sopenharmony_ci	else
3762306a36Sopenharmony_ci		cid = GET_CID_NUM(ep->ep_cid);
3862306a36Sopenharmony_ci	return cid;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type
4462306a36Sopenharmony_ci * @hba: 		Adapter for which adjustments is to be made
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Only applicable to 57710 family of devices
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	u32 num_elements_per_pg;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) ||
5362306a36Sopenharmony_ci	    test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) ||
5462306a36Sopenharmony_ci	    test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
5562306a36Sopenharmony_ci		if (!is_power_of_2(hba->max_sqes))
5662306a36Sopenharmony_ci			hba->max_sqes = rounddown_pow_of_two(hba->max_sqes);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		if (!is_power_of_2(hba->max_rqes))
5962306a36Sopenharmony_ci			hba->max_rqes = rounddown_pow_of_two(hba->max_rqes);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* Adjust each queue size if the user selection does not
6362306a36Sopenharmony_ci	 * yield integral num of page buffers
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	/* adjust SQ */
6662306a36Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
6762306a36Sopenharmony_ci	if (hba->max_sqes < num_elements_per_pg)
6862306a36Sopenharmony_ci		hba->max_sqes = num_elements_per_pg;
6962306a36Sopenharmony_ci	else if (hba->max_sqes % num_elements_per_pg)
7062306a36Sopenharmony_ci		hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) &
7162306a36Sopenharmony_ci				 ~(num_elements_per_pg - 1);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* adjust CQ */
7462306a36Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
7562306a36Sopenharmony_ci	if (hba->max_cqes < num_elements_per_pg)
7662306a36Sopenharmony_ci		hba->max_cqes = num_elements_per_pg;
7762306a36Sopenharmony_ci	else if (hba->max_cqes % num_elements_per_pg)
7862306a36Sopenharmony_ci		hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) &
7962306a36Sopenharmony_ci				 ~(num_elements_per_pg - 1);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* adjust RQ */
8262306a36Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
8362306a36Sopenharmony_ci	if (hba->max_rqes < num_elements_per_pg)
8462306a36Sopenharmony_ci		hba->max_rqes = num_elements_per_pg;
8562306a36Sopenharmony_ci	else if (hba->max_rqes % num_elements_per_pg)
8662306a36Sopenharmony_ci		hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) &
8762306a36Sopenharmony_ci				 ~(num_elements_per_pg - 1);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * bnx2i_get_link_state - get network interface link state
9362306a36Sopenharmony_ci * @hba:	adapter instance pointer
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * updates adapter structure flag based on netdev state
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic void bnx2i_get_link_state(struct bnx2i_hba *hba)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
10062306a36Sopenharmony_ci		set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
10162306a36Sopenharmony_ci	else
10262306a36Sopenharmony_ci		clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * bnx2i_iscsi_license_error - displays iscsi license related error message
10862306a36Sopenharmony_ci * @hba:		adapter instance pointer
10962306a36Sopenharmony_ci * @error_code:		error classification
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * Puts out an error log when driver is unable to offload iscsi connection
11262306a36Sopenharmony_ci *	due to license restrictions
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_cistatic void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED)
11762306a36Sopenharmony_ci		/* iSCSI offload not supported on this device */
11862306a36Sopenharmony_ci		printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n",
11962306a36Sopenharmony_ci				hba->netdev->name);
12062306a36Sopenharmony_ci	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED)
12162306a36Sopenharmony_ci		/* iSCSI offload not supported on this LOM device */
12262306a36Sopenharmony_ci		printk(KERN_ERR "bnx2i: LOM is not enable to "
12362306a36Sopenharmony_ci				"offload iSCSI connections, dev=%s\n",
12462306a36Sopenharmony_ci				hba->netdev->name);
12562306a36Sopenharmony_ci	set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification
13162306a36Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
13262306a36Sopenharmony_ci * @action:	action, ARM or DISARM. For now only ARM_CQE is used
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt
13562306a36Sopenharmony_ci *	the driver. EQ event is generated CQ index is hit or at least 1 CQ is
13662306a36Sopenharmony_ci *	outstanding and on chip timer expires
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ciint bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct bnx2i_5771x_cq_db *cq_db;
14162306a36Sopenharmony_ci	u16 cq_index;
14262306a36Sopenharmony_ci	u16 next_index = 0;
14362306a36Sopenharmony_ci	u32 num_active_cmds;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* Coalesce CQ entries only on 10G devices */
14662306a36Sopenharmony_ci	if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
14762306a36Sopenharmony_ci		return 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Do not update CQ DB multiple times before firmware writes
15062306a36Sopenharmony_ci	 * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious
15162306a36Sopenharmony_ci	 * interrupts and other unwanted results
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (action != CNIC_ARM_CQE_FP)
15662306a36Sopenharmony_ci		if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
15762306a36Sopenharmony_ci			return 0;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) {
16062306a36Sopenharmony_ci		num_active_cmds = atomic_read(&ep->num_active_cmds);
16162306a36Sopenharmony_ci		if (num_active_cmds <= event_coal_min)
16262306a36Sopenharmony_ci			next_index = 1;
16362306a36Sopenharmony_ci		else {
16462306a36Sopenharmony_ci			next_index = num_active_cmds >> ep->ec_shift;
16562306a36Sopenharmony_ci			if (next_index > num_active_cmds - event_coal_min)
16662306a36Sopenharmony_ci				next_index = num_active_cmds - event_coal_min;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci		if (!next_index)
16962306a36Sopenharmony_ci			next_index = 1;
17062306a36Sopenharmony_ci		cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
17162306a36Sopenharmony_ci		if (cq_index > ep->qp.cqe_size * 2)
17262306a36Sopenharmony_ci			cq_index -= ep->qp.cqe_size * 2;
17362306a36Sopenharmony_ci		if (!cq_index)
17462306a36Sopenharmony_ci			cq_index = 1;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		cq_db->sqn[0] = cq_index;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci	return next_index;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/**
18362306a36Sopenharmony_ci * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer
18462306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection on which RQ event occurred
18562306a36Sopenharmony_ci * @ptr:		driver buffer to which RQ buffer contents is to
18662306a36Sopenharmony_ci *			be copied
18762306a36Sopenharmony_ci * @len:		length of valid data inside RQ buf
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * Copies RQ buffer contents from shared (DMA'able) memory region to
19062306a36Sopenharmony_ci *	driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and
19162306a36Sopenharmony_ci *	scsi sense info
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_civoid bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	if (!bnx2i_conn->ep->qp.rqe_left)
19662306a36Sopenharmony_ci		return;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	bnx2i_conn->ep->qp.rqe_left--;
19962306a36Sopenharmony_ci	memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len);
20062306a36Sopenharmony_ci	if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) {
20162306a36Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe;
20262306a36Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_idx = 0;
20362306a36Sopenharmony_ci	} else {
20462306a36Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_qe++;
20562306a36Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_idx++;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct bnx2i_5771x_dbell dbell;
21362306a36Sopenharmony_ci	u32 msg;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	memset(&dbell, 0, sizeof(dbell));
21662306a36Sopenharmony_ci	dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE <<
21762306a36Sopenharmony_ci			      B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT);
21862306a36Sopenharmony_ci	msg = *((u32 *)&dbell);
21962306a36Sopenharmony_ci	/* TODO : get doorbell register mapping */
22062306a36Sopenharmony_ci	writel(cpu_to_le32(msg), conn->ep->qp.ctx_base);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/**
22562306a36Sopenharmony_ci * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell
22662306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection on which event to post
22762306a36Sopenharmony_ci * @count:	number of RQ buffer being posted to chip
22862306a36Sopenharmony_ci *
22962306a36Sopenharmony_ci * No need to ring hardware doorbell for 57710 family of devices
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_civoid bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct bnx2i_5771x_sq_rq_db *rq_db;
23462306a36Sopenharmony_ci	u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000);
23562306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	ep->qp.rqe_left += count;
23862306a36Sopenharmony_ci	ep->qp.rq_prod_idx &= 0x7FFF;
23962306a36Sopenharmony_ci	ep->qp.rq_prod_idx += count;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) {
24262306a36Sopenharmony_ci		ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes;
24362306a36Sopenharmony_ci		if (!hi_bit)
24462306a36Sopenharmony_ci			ep->qp.rq_prod_idx |= 0x8000;
24562306a36Sopenharmony_ci	} else
24662306a36Sopenharmony_ci		ep->qp.rq_prod_idx |= hi_bit;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
24962306a36Sopenharmony_ci		rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt;
25062306a36Sopenharmony_ci		rq_db->prod_idx = ep->qp.rq_prod_idx;
25162306a36Sopenharmony_ci		/* no need to ring hardware doorbell for 57710 */
25262306a36Sopenharmony_ci	} else {
25362306a36Sopenharmony_ci		writew(ep->qp.rq_prod_idx,
25462306a36Sopenharmony_ci		       ep->qp.ctx_base + CNIC_RECV_DOORBELL);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/**
26062306a36Sopenharmony_ci * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine
26162306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection to which new SQ entries belong
26262306a36Sopenharmony_ci * @count: 		number of SQ WQEs to post
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family
26562306a36Sopenharmony_ci *	of devices. For 5706/5708/5709 new SQ WQE count is written into the
26662306a36Sopenharmony_ci *	doorbell register
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_cistatic void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct bnx2i_5771x_sq_rq_db *sq_db;
27162306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	atomic_inc(&ep->num_active_cmds);
27462306a36Sopenharmony_ci	wmb();	/* flush SQ WQE memory before the doorbell is rung */
27562306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
27662306a36Sopenharmony_ci		sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
27762306a36Sopenharmony_ci		sq_db->prod_idx = ep->qp.sq_prod_idx;
27862306a36Sopenharmony_ci		bnx2i_ring_577xx_doorbell(bnx2i_conn);
27962306a36Sopenharmony_ci	} else
28062306a36Sopenharmony_ci		writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/**
28562306a36Sopenharmony_ci * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters
28662306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection to which new SQ entries belong
28762306a36Sopenharmony_ci * @count:	number of SQ WQEs to post
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci * this routine will update SQ driver parameters and ring the doorbell
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_cistatic void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn,
29262306a36Sopenharmony_ci					      int count)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	int tmp_cnt;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (count == 1) {
29762306a36Sopenharmony_ci		if (bnx2i_conn->ep->qp.sq_prod_qe ==
29862306a36Sopenharmony_ci		    bnx2i_conn->ep->qp.sq_last_qe)
29962306a36Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe =
30062306a36Sopenharmony_ci						bnx2i_conn->ep->qp.sq_first_qe;
30162306a36Sopenharmony_ci		else
30262306a36Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe++;
30362306a36Sopenharmony_ci	} else {
30462306a36Sopenharmony_ci		if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <=
30562306a36Sopenharmony_ci		    bnx2i_conn->ep->qp.sq_last_qe)
30662306a36Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe += count;
30762306a36Sopenharmony_ci		else {
30862306a36Sopenharmony_ci			tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe -
30962306a36Sopenharmony_ci				bnx2i_conn->ep->qp.sq_prod_qe;
31062306a36Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe =
31162306a36Sopenharmony_ci				&bnx2i_conn->ep->qp.sq_first_qe[count -
31262306a36Sopenharmony_ci								(tmp_cnt + 1)];
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	bnx2i_conn->ep->qp.sq_prod_idx += count;
31662306a36Sopenharmony_ci	/* Ring the doorbell */
31762306a36Sopenharmony_ci	bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/**
32262306a36Sopenharmony_ci * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware
32362306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
32462306a36Sopenharmony_ci * @task: transport layer's command structure pointer which is requesting
32562306a36Sopenharmony_ci *	  a WQE to sent to chip for further processing
32662306a36Sopenharmony_ci *
32762306a36Sopenharmony_ci * prepare and post an iSCSI Login request WQE to CNIC firmware
32862306a36Sopenharmony_ci */
32962306a36Sopenharmony_ciint bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
33062306a36Sopenharmony_ci			   struct iscsi_task *task)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct bnx2i_login_request *login_wqe;
33362306a36Sopenharmony_ci	struct iscsi_login_req *login_hdr;
33462306a36Sopenharmony_ci	u32 dword;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	login_hdr = (struct iscsi_login_req *)task->hdr;
33762306a36Sopenharmony_ci	login_wqe = (struct bnx2i_login_request *)
33862306a36Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	login_wqe->op_code = login_hdr->opcode;
34162306a36Sopenharmony_ci	login_wqe->op_attr = login_hdr->flags;
34262306a36Sopenharmony_ci	login_wqe->version_max = login_hdr->max_version;
34362306a36Sopenharmony_ci	login_wqe->version_min = login_hdr->min_version;
34462306a36Sopenharmony_ci	login_wqe->data_length = ntoh24(login_hdr->dlength);
34562306a36Sopenharmony_ci	login_wqe->isid_lo = *((u32 *) login_hdr->isid);
34662306a36Sopenharmony_ci	login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2);
34762306a36Sopenharmony_ci	login_wqe->tsih = login_hdr->tsih;
34862306a36Sopenharmony_ci	login_wqe->itt = task->itt |
34962306a36Sopenharmony_ci		(ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT);
35062306a36Sopenharmony_ci	login_wqe->cid = login_hdr->cid;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
35362306a36Sopenharmony_ci	login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
35462306a36Sopenharmony_ci	login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
35762306a36Sopenharmony_ci	login_wqe->resp_bd_list_addr_hi =
35862306a36Sopenharmony_ci		(u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) |
36162306a36Sopenharmony_ci		 (bnx2i_conn->gen_pdu.resp_buf_size <<
36262306a36Sopenharmony_ci		  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
36362306a36Sopenharmony_ci	login_wqe->resp_buffer = dword;
36462306a36Sopenharmony_ci	login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
36562306a36Sopenharmony_ci	login_wqe->bd_list_addr_hi =
36662306a36Sopenharmony_ci		(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
36762306a36Sopenharmony_ci	login_wqe->num_bds = 1;
36862306a36Sopenharmony_ci	login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/**
37562306a36Sopenharmony_ci * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware
37662306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
37762306a36Sopenharmony_ci * @mtask:	driver command structure which is requesting
37862306a36Sopenharmony_ci *		a WQE to sent to chip for further processing
37962306a36Sopenharmony_ci *
38062306a36Sopenharmony_ci * prepare and post an iSCSI Login request WQE to CNIC firmware
38162306a36Sopenharmony_ci */
38262306a36Sopenharmony_ciint bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
38362306a36Sopenharmony_ci			 struct iscsi_task *mtask)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
38662306a36Sopenharmony_ci	struct iscsi_tm *tmfabort_hdr;
38762306a36Sopenharmony_ci	struct scsi_cmnd *ref_sc;
38862306a36Sopenharmony_ci	struct iscsi_task *ctask;
38962306a36Sopenharmony_ci	struct bnx2i_tmf_request *tmfabort_wqe;
39062306a36Sopenharmony_ci	u32 dword;
39162306a36Sopenharmony_ci	u32 scsi_lun[2];
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
39462306a36Sopenharmony_ci	tmfabort_wqe = (struct bnx2i_tmf_request *)
39562306a36Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	tmfabort_wqe->op_code = tmfabort_hdr->opcode;
39862306a36Sopenharmony_ci	tmfabort_wqe->op_attr = tmfabort_hdr->flags;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
40162306a36Sopenharmony_ci	tmfabort_wqe->reserved2 = 0;
40262306a36Sopenharmony_ci	tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
40562306a36Sopenharmony_ci	case ISCSI_TM_FUNC_ABORT_TASK:
40662306a36Sopenharmony_ci	case ISCSI_TM_FUNC_TASK_REASSIGN:
40762306a36Sopenharmony_ci		ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
40862306a36Sopenharmony_ci		if (!ctask || !ctask->sc)
40962306a36Sopenharmony_ci			/*
41062306a36Sopenharmony_ci			 * the iscsi layer must have completed the cmd while
41162306a36Sopenharmony_ci			 * was starting up.
41262306a36Sopenharmony_ci			 *
41362306a36Sopenharmony_ci			 * Note: In the case of a SCSI cmd timeout, the task's
41462306a36Sopenharmony_ci			 *       sc is still active; hence ctask->sc != 0
41562306a36Sopenharmony_ci			 *       In this case, the task must be aborted
41662306a36Sopenharmony_ci			 */
41762306a36Sopenharmony_ci			return 0;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		ref_sc = ctask->sc;
42062306a36Sopenharmony_ci		if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
42162306a36Sopenharmony_ci			dword = (ISCSI_TASK_TYPE_WRITE <<
42262306a36Sopenharmony_ci				 ISCSI_CMD_REQUEST_TYPE_SHIFT);
42362306a36Sopenharmony_ci		else
42462306a36Sopenharmony_ci			dword = (ISCSI_TASK_TYPE_READ <<
42562306a36Sopenharmony_ci				 ISCSI_CMD_REQUEST_TYPE_SHIFT);
42662306a36Sopenharmony_ci		tmfabort_wqe->ref_itt = (dword |
42762306a36Sopenharmony_ci					(tmfabort_hdr->rtt & ISCSI_ITT_MASK));
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	default:
43062306a36Sopenharmony_ci		tmfabort_wqe->ref_itt = RESERVED_ITT;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun));
43362306a36Sopenharmony_ci	tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
43462306a36Sopenharmony_ci	tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
43962306a36Sopenharmony_ci	tmfabort_wqe->bd_list_addr_hi = (u32)
44062306a36Sopenharmony_ci				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
44162306a36Sopenharmony_ci	tmfabort_wqe->num_bds = 1;
44262306a36Sopenharmony_ci	tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/**
44962306a36Sopenharmony_ci * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware
45062306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
45162306a36Sopenharmony_ci * @mtask:	driver command structure which is requesting
45262306a36Sopenharmony_ci *		a WQE to sent to chip for further processing
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci * prepare and post an iSCSI Text request WQE to CNIC firmware
45562306a36Sopenharmony_ci */
45662306a36Sopenharmony_ciint bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn,
45762306a36Sopenharmony_ci			  struct iscsi_task *mtask)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct bnx2i_text_request *text_wqe;
46062306a36Sopenharmony_ci	struct iscsi_text *text_hdr;
46162306a36Sopenharmony_ci	u32 dword;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	text_hdr = (struct iscsi_text *)mtask->hdr;
46462306a36Sopenharmony_ci	text_wqe = (struct bnx2i_text_request *) bnx2i_conn->ep->qp.sq_prod_qe;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	memset(text_wqe, 0, sizeof(struct bnx2i_text_request));
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	text_wqe->op_code = text_hdr->opcode;
46962306a36Sopenharmony_ci	text_wqe->op_attr = text_hdr->flags;
47062306a36Sopenharmony_ci	text_wqe->data_length = ntoh24(text_hdr->dlength);
47162306a36Sopenharmony_ci	text_wqe->itt = mtask->itt |
47262306a36Sopenharmony_ci		(ISCSI_TASK_TYPE_MPATH << ISCSI_TEXT_REQUEST_TYPE_SHIFT);
47362306a36Sopenharmony_ci	text_wqe->ttt = be32_to_cpu(text_hdr->ttt);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	text_wqe->cmd_sn = be32_to_cpu(text_hdr->cmdsn);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	text_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
47862306a36Sopenharmony_ci	text_wqe->resp_bd_list_addr_hi =
47962306a36Sopenharmony_ci			(u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	dword = ((1 << ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT) |
48262306a36Sopenharmony_ci		 (bnx2i_conn->gen_pdu.resp_buf_size <<
48362306a36Sopenharmony_ci		  ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
48462306a36Sopenharmony_ci	text_wqe->resp_buffer = dword;
48562306a36Sopenharmony_ci	text_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
48662306a36Sopenharmony_ci	text_wqe->bd_list_addr_hi =
48762306a36Sopenharmony_ci			(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
48862306a36Sopenharmony_ci	text_wqe->num_bds = 1;
48962306a36Sopenharmony_ci	text_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
49262306a36Sopenharmony_ci	return 0;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/**
49762306a36Sopenharmony_ci * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
49862306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
49962306a36Sopenharmony_ci * @cmd:	driver command structure which is requesting
50062306a36Sopenharmony_ci *		a WQE to sent to chip for further processing
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_ciint bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
50562306a36Sopenharmony_ci			     struct bnx2i_cmd *cmd)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct bnx2i_cmd_request *scsi_cmd_wqe;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	scsi_cmd_wqe = (struct bnx2i_cmd_request *)
51062306a36Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
51162306a36Sopenharmony_ci	memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request));
51262306a36Sopenharmony_ci	scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
51562306a36Sopenharmony_ci	return 0;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/**
51962306a36Sopenharmony_ci * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware
52062306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection
52162306a36Sopenharmony_ci * @task:		transport layer's command structure pointer which is
52262306a36Sopenharmony_ci *                      requesting a WQE to sent to chip for further processing
52362306a36Sopenharmony_ci * @datap:		payload buffer pointer
52462306a36Sopenharmony_ci * @data_len:		payload data length
52562306a36Sopenharmony_ci * @unsol:		indicated whether nopout pdu is unsolicited pdu or
52662306a36Sopenharmony_ci *			in response to target's NOPIN w/ TTT != FFFFFFFF
52762306a36Sopenharmony_ci *
52862306a36Sopenharmony_ci * prepare and post a nopout request WQE to CNIC firmware
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_ciint bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
53162306a36Sopenharmony_ci			    struct iscsi_task *task,
53262306a36Sopenharmony_ci			    char *datap, int data_len, int unsol)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
53562306a36Sopenharmony_ci	struct bnx2i_nop_out_request *nopout_wqe;
53662306a36Sopenharmony_ci	struct iscsi_nopout *nopout_hdr;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	nopout_hdr = (struct iscsi_nopout *)task->hdr;
53962306a36Sopenharmony_ci	nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	memset(nopout_wqe, 0x00, sizeof(struct bnx2i_nop_out_request));
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	nopout_wqe->op_code = nopout_hdr->opcode;
54462306a36Sopenharmony_ci	nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
54562306a36Sopenharmony_ci	memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* 57710 requires LUN field to be swapped */
54862306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
54962306a36Sopenharmony_ci		swap(nopout_wqe->lun[0], nopout_wqe->lun[1]);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	nopout_wqe->itt = ((u16)task->itt |
55262306a36Sopenharmony_ci			   (ISCSI_TASK_TYPE_MPATH <<
55362306a36Sopenharmony_ci			    ISCSI_TMF_REQUEST_TYPE_SHIFT));
55462306a36Sopenharmony_ci	nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt);
55562306a36Sopenharmony_ci	nopout_wqe->flags = 0;
55662306a36Sopenharmony_ci	if (!unsol)
55762306a36Sopenharmony_ci		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
55862306a36Sopenharmony_ci	else if (nopout_hdr->itt == RESERVED_ITT)
55962306a36Sopenharmony_ci		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
56262306a36Sopenharmony_ci	nopout_wqe->data_length = data_len;
56362306a36Sopenharmony_ci	if (data_len) {
56462306a36Sopenharmony_ci		/* handle payload data, not required in first release */
56562306a36Sopenharmony_ci		printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n");
56662306a36Sopenharmony_ci	} else {
56762306a36Sopenharmony_ci		nopout_wqe->bd_list_addr_lo = (u32)
56862306a36Sopenharmony_ci					bnx2i_conn->hba->mp_bd_dma;
56962306a36Sopenharmony_ci		nopout_wqe->bd_list_addr_hi =
57062306a36Sopenharmony_ci			(u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
57162306a36Sopenharmony_ci		nopout_wqe->num_bds = 1;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci	nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci/**
58162306a36Sopenharmony_ci * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware
58262306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
58362306a36Sopenharmony_ci * @task:	transport layer's command structure pointer which is
58462306a36Sopenharmony_ci *		requesting a WQE to sent to chip for further processing
58562306a36Sopenharmony_ci *
58662306a36Sopenharmony_ci * prepare and post logout request WQE to CNIC firmware
58762306a36Sopenharmony_ci */
58862306a36Sopenharmony_ciint bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
58962306a36Sopenharmony_ci			    struct iscsi_task *task)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	struct bnx2i_logout_request *logout_wqe;
59262306a36Sopenharmony_ci	struct iscsi_logout *logout_hdr;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	logout_hdr = (struct iscsi_logout *)task->hdr;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	logout_wqe = (struct bnx2i_logout_request *)
59762306a36Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
59862306a36Sopenharmony_ci	memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	logout_wqe->op_code = logout_hdr->opcode;
60162306a36Sopenharmony_ci	logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
60262306a36Sopenharmony_ci	logout_wqe->op_attr =
60362306a36Sopenharmony_ci			logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE;
60462306a36Sopenharmony_ci	logout_wqe->itt = ((u16)task->itt |
60562306a36Sopenharmony_ci			   (ISCSI_TASK_TYPE_MPATH <<
60662306a36Sopenharmony_ci			    ISCSI_LOGOUT_REQUEST_TYPE_SHIFT));
60762306a36Sopenharmony_ci	logout_wqe->data_length = 0;
60862306a36Sopenharmony_ci	logout_wqe->cid = 0;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
61162306a36Sopenharmony_ci	logout_wqe->bd_list_addr_hi = (u32)
61262306a36Sopenharmony_ci				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
61362306a36Sopenharmony_ci	logout_wqe->num_bds = 1;
61462306a36Sopenharmony_ci	logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
61962306a36Sopenharmony_ci	return 0;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/**
62462306a36Sopenharmony_ci * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware
62562306a36Sopenharmony_ci * @conn:	iscsi connection which requires iscsi parameter update
62662306a36Sopenharmony_ci *
62762306a36Sopenharmony_ci * sends down iSCSI Conn Update request to move iSCSI conn to FFP
62862306a36Sopenharmony_ci */
62962306a36Sopenharmony_civoid bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
63262306a36Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
63362306a36Sopenharmony_ci	struct kwqe *kwqe_arr[2];
63462306a36Sopenharmony_ci	struct iscsi_kwqe_conn_update *update_wqe;
63562306a36Sopenharmony_ci	struct iscsi_kwqe_conn_update conn_update_kwqe;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	update_wqe = &conn_update_kwqe;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN;
64062306a36Sopenharmony_ci	update_wqe->hdr.flags =
64162306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* 5771x requires conn context id to be passed as is */
64462306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type))
64562306a36Sopenharmony_ci		update_wqe->context_id = bnx2i_conn->ep->ep_cid;
64662306a36Sopenharmony_ci	else
64762306a36Sopenharmony_ci		update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7);
64862306a36Sopenharmony_ci	update_wqe->conn_flags = 0;
64962306a36Sopenharmony_ci	if (conn->hdrdgst_en)
65062306a36Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST;
65162306a36Sopenharmony_ci	if (conn->datadgst_en)
65262306a36Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST;
65362306a36Sopenharmony_ci	if (conn->session->initial_r2t_en)
65462306a36Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T;
65562306a36Sopenharmony_ci	if (conn->session->imm_data_en)
65662306a36Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	update_wqe->max_send_pdu_length = conn->max_xmit_dlength;
65962306a36Sopenharmony_ci	update_wqe->max_recv_pdu_length = conn->max_recv_dlength;
66062306a36Sopenharmony_ci	update_wqe->first_burst_length = conn->session->first_burst;
66162306a36Sopenharmony_ci	update_wqe->max_burst_length = conn->session->max_burst;
66262306a36Sopenharmony_ci	update_wqe->exp_stat_sn = conn->exp_statsn;
66362306a36Sopenharmony_ci	update_wqe->max_outstanding_r2ts = conn->session->max_r2t;
66462306a36Sopenharmony_ci	update_wqe->session_error_recovery_level = conn->session->erl;
66562306a36Sopenharmony_ci	iscsi_conn_printk(KERN_ALERT, conn,
66662306a36Sopenharmony_ci			  "bnx2i: conn update - MBL 0x%x FBL 0x%x"
66762306a36Sopenharmony_ci			  "MRDSL_I 0x%x MRDSL_T 0x%x \n",
66862306a36Sopenharmony_ci			  update_wqe->max_burst_length,
66962306a36Sopenharmony_ci			  update_wqe->first_burst_length,
67062306a36Sopenharmony_ci			  update_wqe->max_recv_pdu_length,
67162306a36Sopenharmony_ci			  update_wqe->max_send_pdu_length);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) update_wqe;
67462306a36Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
67562306a36Sopenharmony_ci		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci/**
68062306a36Sopenharmony_ci * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware
68162306a36Sopenharmony_ci * @t:	timer context used to fetch the endpoint (transport
68262306a36Sopenharmony_ci *	handle) structure pointer
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * routine to handle connection offload/destroy request timeout
68562306a36Sopenharmony_ci */
68662306a36Sopenharmony_civoid bnx2i_ep_ofld_timer(struct timer_list *t)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = from_timer(ep, t, ofld_timer);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (ep->state == EP_STATE_OFLD_START) {
69162306a36Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n");
69262306a36Sopenharmony_ci		ep->state = EP_STATE_OFLD_FAILED;
69362306a36Sopenharmony_ci	} else if (ep->state == EP_STATE_DISCONN_START) {
69462306a36Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n");
69562306a36Sopenharmony_ci		ep->state = EP_STATE_DISCONN_TIMEDOUT;
69662306a36Sopenharmony_ci	} else if (ep->state == EP_STATE_CLEANUP_START) {
69762306a36Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n");
69862306a36Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_FAILED;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic int bnx2i_power_of2(u32 val)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	u32 power = 0;
70862306a36Sopenharmony_ci	if (val & (val - 1))
70962306a36Sopenharmony_ci		return power;
71062306a36Sopenharmony_ci	val--;
71162306a36Sopenharmony_ci	while (val) {
71262306a36Sopenharmony_ci		val = val >> 1;
71362306a36Sopenharmony_ci		power++;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci	return power;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/**
72062306a36Sopenharmony_ci * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request
72162306a36Sopenharmony_ci * @hba:	adapter structure pointer
72262306a36Sopenharmony_ci * @cmd:	driver command structure which is requesting
72362306a36Sopenharmony_ci *		a WQE to sent to chip for further processing
72462306a36Sopenharmony_ci *
72562306a36Sopenharmony_ci * prepares and posts CONN_OFLD_REQ1/2 KWQE
72662306a36Sopenharmony_ci */
72762306a36Sopenharmony_civoid bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct bnx2i_cleanup_request *cmd_cleanup;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	cmd_cleanup =
73262306a36Sopenharmony_ci		(struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe;
73362306a36Sopenharmony_ci	memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request));
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST;
73662306a36Sopenharmony_ci	cmd_cleanup->itt = cmd->req.itt;
73762306a36Sopenharmony_ci	cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(cmd->conn, 1);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci/**
74462306a36Sopenharmony_ci * bnx2i_send_conn_destroy - initiates iscsi connection teardown process
74562306a36Sopenharmony_ci * @hba:	adapter structure pointer
74662306a36Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
74762306a36Sopenharmony_ci *
74862306a36Sopenharmony_ci * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
74962306a36Sopenharmony_ci * 	iscsi connection context clean-up process
75062306a36Sopenharmony_ci */
75162306a36Sopenharmony_ciint bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct kwqe *kwqe_arr[2];
75462306a36Sopenharmony_ci	struct iscsi_kwqe_conn_destroy conn_cleanup;
75562306a36Sopenharmony_ci	int rc = -EINVAL;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN;
76062306a36Sopenharmony_ci	conn_cleanup.hdr.flags =
76162306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
76262306a36Sopenharmony_ci	/* 5771x requires conn context id to be passed as is */
76362306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
76462306a36Sopenharmony_ci		conn_cleanup.context_id = ep->ep_cid;
76562306a36Sopenharmony_ci	else
76662306a36Sopenharmony_ci		conn_cleanup.context_id = (ep->ep_cid >> 7);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
77162306a36Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
77262306a36Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	return rc;
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/**
77962306a36Sopenharmony_ci * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process
78062306a36Sopenharmony_ci * @hba: 		adapter structure pointer
78162306a36Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
78262306a36Sopenharmony_ci *
78362306a36Sopenharmony_ci * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
78662306a36Sopenharmony_ci					 struct bnx2i_endpoint *ep)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct kwqe *kwqe_arr[2];
78962306a36Sopenharmony_ci	struct iscsi_kwqe_conn_offload1 ofld_req1;
79062306a36Sopenharmony_ci	struct iscsi_kwqe_conn_offload2 ofld_req2;
79162306a36Sopenharmony_ci	dma_addr_t dma_addr;
79262306a36Sopenharmony_ci	int num_kwqes = 2;
79362306a36Sopenharmony_ci	u32 *ptbl;
79462306a36Sopenharmony_ci	int rc = -EINVAL;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
79762306a36Sopenharmony_ci	ofld_req1.hdr.flags =
79862306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	dma_addr = ep->qp.sq_pgtbl_phys;
80362306a36Sopenharmony_ci	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
80462306a36Sopenharmony_ci	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	dma_addr = ep->qp.cq_pgtbl_phys;
80762306a36Sopenharmony_ci	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
80862306a36Sopenharmony_ci	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
81162306a36Sopenharmony_ci	ofld_req2.hdr.flags =
81262306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	dma_addr = ep->qp.rq_pgtbl_phys;
81562306a36Sopenharmony_ci	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
81662306a36Sopenharmony_ci	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	ofld_req2.sq_first_pte.hi = *ptbl++;
82162306a36Sopenharmony_ci	ofld_req2.sq_first_pte.lo = *ptbl;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
82462306a36Sopenharmony_ci	ofld_req2.cq_first_pte.hi = *ptbl++;
82562306a36Sopenharmony_ci	ofld_req2.cq_first_pte.lo = *ptbl;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
82862306a36Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
82962306a36Sopenharmony_ci	ofld_req2.num_additional_wqes = 0;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
83262306a36Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return rc;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci/**
83962306a36Sopenharmony_ci * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation
84062306a36Sopenharmony_ci * @hba: 		adapter structure pointer
84162306a36Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
84262306a36Sopenharmony_ci *
84362306a36Sopenharmony_ci * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
84462306a36Sopenharmony_ci */
84562306a36Sopenharmony_cistatic int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
84662306a36Sopenharmony_ci					  struct bnx2i_endpoint *ep)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct kwqe *kwqe_arr[5];
84962306a36Sopenharmony_ci	struct iscsi_kwqe_conn_offload1 ofld_req1;
85062306a36Sopenharmony_ci	struct iscsi_kwqe_conn_offload2 ofld_req2;
85162306a36Sopenharmony_ci	struct iscsi_kwqe_conn_offload3 ofld_req3[1];
85262306a36Sopenharmony_ci	dma_addr_t dma_addr;
85362306a36Sopenharmony_ci	int num_kwqes = 2;
85462306a36Sopenharmony_ci	u32 *ptbl;
85562306a36Sopenharmony_ci	int rc = -EINVAL;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
85862306a36Sopenharmony_ci	ofld_req1.hdr.flags =
85962306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE;
86462306a36Sopenharmony_ci	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
86562306a36Sopenharmony_ci	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE;
86862306a36Sopenharmony_ci	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
86962306a36Sopenharmony_ci	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
87262306a36Sopenharmony_ci	ofld_req2.hdr.flags =
87362306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE;
87662306a36Sopenharmony_ci	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
87762306a36Sopenharmony_ci	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
88062306a36Sopenharmony_ci	ofld_req2.sq_first_pte.hi = *ptbl++;
88162306a36Sopenharmony_ci	ofld_req2.sq_first_pte.lo = *ptbl;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
88462306a36Sopenharmony_ci	ofld_req2.cq_first_pte.hi = *ptbl++;
88562306a36Sopenharmony_ci	ofld_req2.cq_first_pte.lo = *ptbl;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
88862306a36Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	ofld_req2.num_additional_wqes = 1;
89162306a36Sopenharmony_ci	memset(ofld_req3, 0x00, sizeof(ofld_req3[0]));
89262306a36Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
89362306a36Sopenharmony_ci	ofld_req3[0].qp_first_pte[0].hi = *ptbl++;
89462306a36Sopenharmony_ci	ofld_req3[0].qp_first_pte[0].lo = *ptbl;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	kwqe_arr[2] = (struct kwqe *) ofld_req3;
89762306a36Sopenharmony_ci	/* need if we decide to go with multiple KCQE's per conn */
89862306a36Sopenharmony_ci	num_kwqes += 1;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
90162306a36Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	return rc;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci/**
90762306a36Sopenharmony_ci * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process
90862306a36Sopenharmony_ci *
90962306a36Sopenharmony_ci * @hba: 		adapter structure pointer
91062306a36Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
91362306a36Sopenharmony_ci */
91462306a36Sopenharmony_ciint bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	int rc;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
91962306a36Sopenharmony_ci		rc = bnx2i_5771x_send_conn_ofld_req(hba, ep);
92062306a36Sopenharmony_ci	else
92162306a36Sopenharmony_ci		rc = bnx2i_570x_send_conn_ofld_req(hba, ep);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return rc;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci/**
92862306a36Sopenharmony_ci * setup_qp_page_tables - iscsi QP page table setup function
92962306a36Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
93062306a36Sopenharmony_ci *
93162306a36Sopenharmony_ci * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires
93262306a36Sopenharmony_ci * 	64-bit address in big endian format. Whereas 10G/sec (57710) requires
93362306a36Sopenharmony_ci * 	PT in little endian format
93462306a36Sopenharmony_ci */
93562306a36Sopenharmony_cistatic void setup_qp_page_tables(struct bnx2i_endpoint *ep)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	int num_pages;
93862306a36Sopenharmony_ci	u32 *ptbl;
93962306a36Sopenharmony_ci	dma_addr_t page;
94062306a36Sopenharmony_ci	int cnic_dev_10g;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
94362306a36Sopenharmony_ci		cnic_dev_10g = 1;
94462306a36Sopenharmony_ci	else
94562306a36Sopenharmony_ci		cnic_dev_10g = 0;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	/* SQ page table */
94862306a36Sopenharmony_ci	memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
94962306a36Sopenharmony_ci	num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
95062306a36Sopenharmony_ci	page = ep->qp.sq_phys;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (cnic_dev_10g)
95362306a36Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
95462306a36Sopenharmony_ci	else
95562306a36Sopenharmony_ci		ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
95662306a36Sopenharmony_ci	while (num_pages--) {
95762306a36Sopenharmony_ci		if (cnic_dev_10g) {
95862306a36Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
95962306a36Sopenharmony_ci			*ptbl = (u32) page;
96062306a36Sopenharmony_ci			ptbl++;
96162306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
96262306a36Sopenharmony_ci			ptbl++;
96362306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
96462306a36Sopenharmony_ci		} else {
96562306a36Sopenharmony_ci			/* PTE is written in big endian format for
96662306a36Sopenharmony_ci			 * 5706/5708/5709 devices */
96762306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
96862306a36Sopenharmony_ci			ptbl++;
96962306a36Sopenharmony_ci			*ptbl = (u32) page;
97062306a36Sopenharmony_ci			ptbl++;
97162306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/* RQ page table */
97662306a36Sopenharmony_ci	memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
97762306a36Sopenharmony_ci	num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
97862306a36Sopenharmony_ci	page = ep->qp.rq_phys;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (cnic_dev_10g)
98162306a36Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
98262306a36Sopenharmony_ci	else
98362306a36Sopenharmony_ci		ptbl = (u32 *) ep->qp.rq_pgtbl_virt;
98462306a36Sopenharmony_ci	while (num_pages--) {
98562306a36Sopenharmony_ci		if (cnic_dev_10g) {
98662306a36Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
98762306a36Sopenharmony_ci			*ptbl = (u32) page;
98862306a36Sopenharmony_ci			ptbl++;
98962306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
99062306a36Sopenharmony_ci			ptbl++;
99162306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
99262306a36Sopenharmony_ci		} else {
99362306a36Sopenharmony_ci			/* PTE is written in big endian format for
99462306a36Sopenharmony_ci			 * 5706/5708/5709 devices */
99562306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
99662306a36Sopenharmony_ci			ptbl++;
99762306a36Sopenharmony_ci			*ptbl = (u32) page;
99862306a36Sopenharmony_ci			ptbl++;
99962306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
100062306a36Sopenharmony_ci		}
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* CQ page table */
100462306a36Sopenharmony_ci	memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
100562306a36Sopenharmony_ci	num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
100662306a36Sopenharmony_ci	page = ep->qp.cq_phys;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (cnic_dev_10g)
100962306a36Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
101062306a36Sopenharmony_ci	else
101162306a36Sopenharmony_ci		ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
101262306a36Sopenharmony_ci	while (num_pages--) {
101362306a36Sopenharmony_ci		if (cnic_dev_10g) {
101462306a36Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
101562306a36Sopenharmony_ci			*ptbl = (u32) page;
101662306a36Sopenharmony_ci			ptbl++;
101762306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
101862306a36Sopenharmony_ci			ptbl++;
101962306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
102062306a36Sopenharmony_ci		} else {
102162306a36Sopenharmony_ci			/* PTE is written in big endian format for
102262306a36Sopenharmony_ci			 * 5706/5708/5709 devices */
102362306a36Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
102462306a36Sopenharmony_ci			ptbl++;
102562306a36Sopenharmony_ci			*ptbl = (u32) page;
102662306a36Sopenharmony_ci			ptbl++;
102762306a36Sopenharmony_ci			page += CNIC_PAGE_SIZE;
102862306a36Sopenharmony_ci		}
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/**
103462306a36Sopenharmony_ci * bnx2i_alloc_qp_resc - allocates required resources for QP.
103562306a36Sopenharmony_ci * @hba:	adapter structure pointer
103662306a36Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * Allocate QP (transport layer for iSCSI connection) resources, DMA'able
103962306a36Sopenharmony_ci *	memory for SQ/RQ/CQ and page tables. EP structure elements such
104062306a36Sopenharmony_ci *	as producer/consumer indexes/pointers, queue sizes and page table
104162306a36Sopenharmony_ci *	contents are setup
104262306a36Sopenharmony_ci */
104362306a36Sopenharmony_ciint bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct bnx2i_5771x_cq_db *cq_db;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	ep->hba = hba;
104862306a36Sopenharmony_ci	ep->conn = NULL;
104962306a36Sopenharmony_ci	ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* Allocate page table memory for SQ which is page aligned */
105262306a36Sopenharmony_ci	ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
105362306a36Sopenharmony_ci	ep->qp.sq_mem_size =
105462306a36Sopenharmony_ci		(ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
105562306a36Sopenharmony_ci	ep->qp.sq_pgtbl_size =
105662306a36Sopenharmony_ci		(ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
105762306a36Sopenharmony_ci	ep->qp.sq_pgtbl_size =
105862306a36Sopenharmony_ci		(ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	ep->qp.sq_pgtbl_virt =
106162306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
106262306a36Sopenharmony_ci				   &ep->qp.sq_pgtbl_phys, GFP_KERNEL);
106362306a36Sopenharmony_ci	if (!ep->qp.sq_pgtbl_virt) {
106462306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n",
106562306a36Sopenharmony_ci				  ep->qp.sq_pgtbl_size);
106662306a36Sopenharmony_ci		goto mem_alloc_err;
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/* Allocate memory area for actual SQ element */
107062306a36Sopenharmony_ci	ep->qp.sq_virt =
107162306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
107262306a36Sopenharmony_ci				   &ep->qp.sq_phys, GFP_KERNEL);
107362306a36Sopenharmony_ci	if (!ep->qp.sq_virt) {
107462306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n",
107562306a36Sopenharmony_ci				  ep->qp.sq_mem_size);
107662306a36Sopenharmony_ci		goto mem_alloc_err;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	ep->qp.sq_first_qe = ep->qp.sq_virt;
108062306a36Sopenharmony_ci	ep->qp.sq_prod_qe = ep->qp.sq_first_qe;
108162306a36Sopenharmony_ci	ep->qp.sq_cons_qe = ep->qp.sq_first_qe;
108262306a36Sopenharmony_ci	ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1];
108362306a36Sopenharmony_ci	ep->qp.sq_prod_idx = 0;
108462306a36Sopenharmony_ci	ep->qp.sq_cons_idx = 0;
108562306a36Sopenharmony_ci	ep->qp.sqe_left = hba->max_sqes;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	/* Allocate page table memory for CQ which is page aligned */
108862306a36Sopenharmony_ci	ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
108962306a36Sopenharmony_ci	ep->qp.cq_mem_size =
109062306a36Sopenharmony_ci		(ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
109162306a36Sopenharmony_ci	ep->qp.cq_pgtbl_size =
109262306a36Sopenharmony_ci		(ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
109362306a36Sopenharmony_ci	ep->qp.cq_pgtbl_size =
109462306a36Sopenharmony_ci		(ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	ep->qp.cq_pgtbl_virt =
109762306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
109862306a36Sopenharmony_ci				   &ep->qp.cq_pgtbl_phys, GFP_KERNEL);
109962306a36Sopenharmony_ci	if (!ep->qp.cq_pgtbl_virt) {
110062306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n",
110162306a36Sopenharmony_ci				  ep->qp.cq_pgtbl_size);
110262306a36Sopenharmony_ci		goto mem_alloc_err;
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* Allocate memory area for actual CQ element */
110662306a36Sopenharmony_ci	ep->qp.cq_virt =
110762306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
110862306a36Sopenharmony_ci				   &ep->qp.cq_phys, GFP_KERNEL);
110962306a36Sopenharmony_ci	if (!ep->qp.cq_virt) {
111062306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n",
111162306a36Sopenharmony_ci				  ep->qp.cq_mem_size);
111262306a36Sopenharmony_ci		goto mem_alloc_err;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	ep->qp.cq_first_qe = ep->qp.cq_virt;
111662306a36Sopenharmony_ci	ep->qp.cq_prod_qe = ep->qp.cq_first_qe;
111762306a36Sopenharmony_ci	ep->qp.cq_cons_qe = ep->qp.cq_first_qe;
111862306a36Sopenharmony_ci	ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1];
111962306a36Sopenharmony_ci	ep->qp.cq_prod_idx = 0;
112062306a36Sopenharmony_ci	ep->qp.cq_cons_idx = 0;
112162306a36Sopenharmony_ci	ep->qp.cqe_left = hba->max_cqes;
112262306a36Sopenharmony_ci	ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN;
112362306a36Sopenharmony_ci	ep->qp.cqe_size = hba->max_cqes;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* Invalidate all EQ CQE index, req only for 57710 */
112662306a36Sopenharmony_ci	cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
112762306a36Sopenharmony_ci	memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Allocate page table memory for RQ which is page aligned */
113062306a36Sopenharmony_ci	ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
113162306a36Sopenharmony_ci	ep->qp.rq_mem_size =
113262306a36Sopenharmony_ci		(ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
113362306a36Sopenharmony_ci	ep->qp.rq_pgtbl_size =
113462306a36Sopenharmony_ci		(ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
113562306a36Sopenharmony_ci	ep->qp.rq_pgtbl_size =
113662306a36Sopenharmony_ci		(ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	ep->qp.rq_pgtbl_virt =
113962306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
114062306a36Sopenharmony_ci				   &ep->qp.rq_pgtbl_phys, GFP_KERNEL);
114162306a36Sopenharmony_ci	if (!ep->qp.rq_pgtbl_virt) {
114262306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n",
114362306a36Sopenharmony_ci				  ep->qp.rq_pgtbl_size);
114462306a36Sopenharmony_ci		goto mem_alloc_err;
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* Allocate memory area for actual RQ element */
114862306a36Sopenharmony_ci	ep->qp.rq_virt =
114962306a36Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
115062306a36Sopenharmony_ci				   &ep->qp.rq_phys, GFP_KERNEL);
115162306a36Sopenharmony_ci	if (!ep->qp.rq_virt) {
115262306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n",
115362306a36Sopenharmony_ci				  ep->qp.rq_mem_size);
115462306a36Sopenharmony_ci		goto mem_alloc_err;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	ep->qp.rq_first_qe = ep->qp.rq_virt;
115862306a36Sopenharmony_ci	ep->qp.rq_prod_qe = ep->qp.rq_first_qe;
115962306a36Sopenharmony_ci	ep->qp.rq_cons_qe = ep->qp.rq_first_qe;
116062306a36Sopenharmony_ci	ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1];
116162306a36Sopenharmony_ci	ep->qp.rq_prod_idx = 0x8000;
116262306a36Sopenharmony_ci	ep->qp.rq_cons_idx = 0;
116362306a36Sopenharmony_ci	ep->qp.rqe_left = hba->max_rqes;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	setup_qp_page_tables(ep);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	return 0;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cimem_alloc_err:
117062306a36Sopenharmony_ci	bnx2i_free_qp_resc(hba, ep);
117162306a36Sopenharmony_ci	return -ENOMEM;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci/**
117762306a36Sopenharmony_ci * bnx2i_free_qp_resc - free memory resources held by QP
117862306a36Sopenharmony_ci * @hba:	adapter structure pointer
117962306a36Sopenharmony_ci * @ep:	endpoint (transport identifier) structure
118062306a36Sopenharmony_ci *
118162306a36Sopenharmony_ci * Free QP resources - SQ/RQ/CQ memory and page tables.
118262306a36Sopenharmony_ci */
118362306a36Sopenharmony_civoid bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	if (ep->qp.ctx_base) {
118662306a36Sopenharmony_ci		iounmap(ep->qp.ctx_base);
118762306a36Sopenharmony_ci		ep->qp.ctx_base = NULL;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci	/* Free SQ mem */
119062306a36Sopenharmony_ci	if (ep->qp.sq_pgtbl_virt) {
119162306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
119262306a36Sopenharmony_ci				  ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys);
119362306a36Sopenharmony_ci		ep->qp.sq_pgtbl_virt = NULL;
119462306a36Sopenharmony_ci		ep->qp.sq_pgtbl_phys = 0;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci	if (ep->qp.sq_virt) {
119762306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
119862306a36Sopenharmony_ci				  ep->qp.sq_virt, ep->qp.sq_phys);
119962306a36Sopenharmony_ci		ep->qp.sq_virt = NULL;
120062306a36Sopenharmony_ci		ep->qp.sq_phys = 0;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* Free RQ mem */
120462306a36Sopenharmony_ci	if (ep->qp.rq_pgtbl_virt) {
120562306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
120662306a36Sopenharmony_ci				  ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys);
120762306a36Sopenharmony_ci		ep->qp.rq_pgtbl_virt = NULL;
120862306a36Sopenharmony_ci		ep->qp.rq_pgtbl_phys = 0;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci	if (ep->qp.rq_virt) {
121162306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
121262306a36Sopenharmony_ci				  ep->qp.rq_virt, ep->qp.rq_phys);
121362306a36Sopenharmony_ci		ep->qp.rq_virt = NULL;
121462306a36Sopenharmony_ci		ep->qp.rq_phys = 0;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	/* Free CQ mem */
121862306a36Sopenharmony_ci	if (ep->qp.cq_pgtbl_virt) {
121962306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
122062306a36Sopenharmony_ci				  ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys);
122162306a36Sopenharmony_ci		ep->qp.cq_pgtbl_virt = NULL;
122262306a36Sopenharmony_ci		ep->qp.cq_pgtbl_phys = 0;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci	if (ep->qp.cq_virt) {
122562306a36Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
122662306a36Sopenharmony_ci				  ep->qp.cq_virt, ep->qp.cq_phys);
122762306a36Sopenharmony_ci		ep->qp.cq_virt = NULL;
122862306a36Sopenharmony_ci		ep->qp.cq_phys = 0;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/**
123462306a36Sopenharmony_ci * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w
123562306a36Sopenharmony_ci * @hba:	adapter structure pointer
123662306a36Sopenharmony_ci *
123762306a36Sopenharmony_ci * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w
123862306a36Sopenharmony_ci * 	This results in iSCSi support validation and on-chip context manager
123962306a36Sopenharmony_ci * 	initialization.  Firmware completes this handshake with a CQE carrying
124062306a36Sopenharmony_ci * 	the result of iscsi support validation. Parameter carried by
124162306a36Sopenharmony_ci * 	iscsi init request determines the number of offloaded connection and
124262306a36Sopenharmony_ci * 	tolerance level for iscsi protocol violation this hba/chip can support
124362306a36Sopenharmony_ci */
124462306a36Sopenharmony_ciint bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct kwqe *kwqe_arr[3];
124762306a36Sopenharmony_ci	struct iscsi_kwqe_init1 iscsi_init;
124862306a36Sopenharmony_ci	struct iscsi_kwqe_init2 iscsi_init2;
124962306a36Sopenharmony_ci	int rc = 0;
125062306a36Sopenharmony_ci	u64 mask64;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1));
125362306a36Sopenharmony_ci	memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2));
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	bnx2i_adjust_qp_size(hba);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	iscsi_init.flags =
125862306a36Sopenharmony_ci		(CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
125962306a36Sopenharmony_ci	if (en_tcp_dack)
126062306a36Sopenharmony_ci		iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
126162306a36Sopenharmony_ci	iscsi_init.reserved0 = 0;
126262306a36Sopenharmony_ci	iscsi_init.num_cqs = 1;
126362306a36Sopenharmony_ci	iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1;
126462306a36Sopenharmony_ci	iscsi_init.hdr.flags =
126562306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma;
126862306a36Sopenharmony_ci	iscsi_init.dummy_buffer_addr_hi =
126962306a36Sopenharmony_ci		(u32) ((u64) hba->dummy_buf_dma >> 32);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	hba->num_ccell = hba->max_sqes >> 1;
127262306a36Sopenharmony_ci	hba->ctx_ccell_tasks =
127362306a36Sopenharmony_ci			((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
127462306a36Sopenharmony_ci	iscsi_init.num_ccells_per_conn = hba->num_ccell;
127562306a36Sopenharmony_ci	iscsi_init.num_tasks_per_conn = hba->max_sqes;
127662306a36Sopenharmony_ci	iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
127762306a36Sopenharmony_ci	iscsi_init.sq_num_wqes = hba->max_sqes;
127862306a36Sopenharmony_ci	iscsi_init.cq_log_wqes_per_page =
127962306a36Sopenharmony_ci		(u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
128062306a36Sopenharmony_ci	iscsi_init.cq_num_wqes = hba->max_cqes;
128162306a36Sopenharmony_ci	iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
128262306a36Sopenharmony_ci				   (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
128362306a36Sopenharmony_ci	iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
128462306a36Sopenharmony_ci				   (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
128562306a36Sopenharmony_ci	iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
128662306a36Sopenharmony_ci	iscsi_init.rq_num_wqes = hba->max_rqes;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2;
129062306a36Sopenharmony_ci	iscsi_init2.hdr.flags =
129162306a36Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
129262306a36Sopenharmony_ci	iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1;
129362306a36Sopenharmony_ci	mask64 = 0x0ULL;
129462306a36Sopenharmony_ci	mask64 |= (
129562306a36Sopenharmony_ci		/* CISCO MDS */
129662306a36Sopenharmony_ci		(1UL <<
129762306a36Sopenharmony_ci		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) |
129862306a36Sopenharmony_ci		/* HP MSA1510i */
129962306a36Sopenharmony_ci		(1UL <<
130062306a36Sopenharmony_ci		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
130162306a36Sopenharmony_ci		/* EMC */
130262306a36Sopenharmony_ci		(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
130362306a36Sopenharmony_ci	if (error_mask1) {
130462306a36Sopenharmony_ci		iscsi_init2.error_bit_map[0] = error_mask1;
130562306a36Sopenharmony_ci		mask64 ^= (u32)(mask64);
130662306a36Sopenharmony_ci		mask64 |= error_mask1;
130762306a36Sopenharmony_ci	} else
130862306a36Sopenharmony_ci		iscsi_init2.error_bit_map[0] = (u32) mask64;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (error_mask2) {
131162306a36Sopenharmony_ci		iscsi_init2.error_bit_map[1] = error_mask2;
131262306a36Sopenharmony_ci		mask64 &= 0xffffffff;
131362306a36Sopenharmony_ci		mask64 |= ((u64)error_mask2 << 32);
131462306a36Sopenharmony_ci	} else
131562306a36Sopenharmony_ci		iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	iscsi_error_mask = mask64;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &iscsi_init;
132062306a36Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &iscsi_init2;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
132362306a36Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2);
132462306a36Sopenharmony_ci	return rc;
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci/**
132962306a36Sopenharmony_ci * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
133062306a36Sopenharmony_ci * @session:	iscsi session
133162306a36Sopenharmony_ci * @bnx2i_conn:	bnx2i connection
133262306a36Sopenharmony_ci * @cqe:	pointer to newly DMA'ed CQE entry for processing
133362306a36Sopenharmony_ci *
133462306a36Sopenharmony_ci * process SCSI CMD Response CQE & complete the request to SCSI-ML
133562306a36Sopenharmony_ci */
133662306a36Sopenharmony_ciint bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
133762306a36Sopenharmony_ci				struct bnx2i_conn *bnx2i_conn,
133862306a36Sopenharmony_ci				struct cqe *cqe)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
134162306a36Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
134262306a36Sopenharmony_ci	struct bnx2i_cmd_response *resp_cqe;
134362306a36Sopenharmony_ci	struct bnx2i_cmd *bnx2i_cmd;
134462306a36Sopenharmony_ci	struct iscsi_task *task;
134562306a36Sopenharmony_ci	struct iscsi_scsi_rsp *hdr;
134662306a36Sopenharmony_ci	u32 datalen = 0;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	resp_cqe = (struct bnx2i_cmd_response *)cqe;
134962306a36Sopenharmony_ci	spin_lock_bh(&session->back_lock);
135062306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
135162306a36Sopenharmony_ci				 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
135262306a36Sopenharmony_ci	if (!task)
135362306a36Sopenharmony_ci		goto fail;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	bnx2i_cmd = task->dd_data;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) {
135862306a36Sopenharmony_ci		conn->datain_pdus_cnt +=
135962306a36Sopenharmony_ci			resp_cqe->task_stat.read_stat.num_data_ins;
136062306a36Sopenharmony_ci		conn->rxdata_octets +=
136162306a36Sopenharmony_ci			bnx2i_cmd->req.total_data_transfer_length;
136262306a36Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus,
136362306a36Sopenharmony_ci			     resp_cqe->task_stat.read_stat.num_data_ins);
136462306a36Sopenharmony_ci		ADD_STATS_64(hba, rx_bytes,
136562306a36Sopenharmony_ci			     bnx2i_cmd->req.total_data_transfer_length);
136662306a36Sopenharmony_ci	} else {
136762306a36Sopenharmony_ci		conn->dataout_pdus_cnt +=
136862306a36Sopenharmony_ci			resp_cqe->task_stat.write_stat.num_data_outs;
136962306a36Sopenharmony_ci		conn->r2t_pdus_cnt +=
137062306a36Sopenharmony_ci			resp_cqe->task_stat.write_stat.num_r2ts;
137162306a36Sopenharmony_ci		conn->txdata_octets +=
137262306a36Sopenharmony_ci			bnx2i_cmd->req.total_data_transfer_length;
137362306a36Sopenharmony_ci		ADD_STATS_64(hba, tx_pdus,
137462306a36Sopenharmony_ci			     resp_cqe->task_stat.write_stat.num_data_outs);
137562306a36Sopenharmony_ci		ADD_STATS_64(hba, tx_bytes,
137662306a36Sopenharmony_ci			     bnx2i_cmd->req.total_data_transfer_length);
137762306a36Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus,
137862306a36Sopenharmony_ci			     resp_cqe->task_stat.write_stat.num_r2ts);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci	bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	hdr = (struct iscsi_scsi_rsp *)task->hdr;
138362306a36Sopenharmony_ci	resp_cqe = (struct bnx2i_cmd_response *)cqe;
138462306a36Sopenharmony_ci	hdr->opcode = resp_cqe->op_code;
138562306a36Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
138662306a36Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn);
138762306a36Sopenharmony_ci	hdr->response = resp_cqe->response;
138862306a36Sopenharmony_ci	hdr->cmd_status = resp_cqe->status;
138962306a36Sopenharmony_ci	hdr->flags = resp_cqe->response_flags;
139062306a36Sopenharmony_ci	hdr->residual_count = cpu_to_be32(resp_cqe->residual_count);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN)
139362306a36Sopenharmony_ci		goto done;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) {
139662306a36Sopenharmony_ci		datalen = resp_cqe->data_length;
139762306a36Sopenharmony_ci		if (datalen < 2)
139862306a36Sopenharmony_ci			goto done;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		if (datalen > BNX2I_RQ_WQE_SIZE) {
140162306a36Sopenharmony_ci			iscsi_conn_printk(KERN_ERR, conn,
140262306a36Sopenharmony_ci					  "sense data len %d > RQ sz\n",
140362306a36Sopenharmony_ci					  datalen);
140462306a36Sopenharmony_ci			datalen = BNX2I_RQ_WQE_SIZE;
140562306a36Sopenharmony_ci		} else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) {
140662306a36Sopenharmony_ci			iscsi_conn_printk(KERN_ERR, conn,
140762306a36Sopenharmony_ci					  "sense data len %d > conn data\n",
140862306a36Sopenharmony_ci					  datalen);
140962306a36Sopenharmony_ci			datalen = ISCSI_DEF_MAX_RECV_SEG_LEN;
141062306a36Sopenharmony_ci		}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci		bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen);
141362306a36Sopenharmony_ci		bnx2i_put_rq_buf(bnx2i_cmd->conn, 1);
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cidone:
141762306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
141862306a36Sopenharmony_ci			     conn->data, datalen);
141962306a36Sopenharmony_cifail:
142062306a36Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
142162306a36Sopenharmony_ci	return 0;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/**
142662306a36Sopenharmony_ci * bnx2i_process_login_resp - this function handles iscsi login response
142762306a36Sopenharmony_ci * @session:		iscsi session pointer
142862306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
142962306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
143062306a36Sopenharmony_ci *
143162306a36Sopenharmony_ci * process Login Response CQE & complete it to open-iscsi user daemon
143262306a36Sopenharmony_ci */
143362306a36Sopenharmony_cistatic int bnx2i_process_login_resp(struct iscsi_session *session,
143462306a36Sopenharmony_ci				    struct bnx2i_conn *bnx2i_conn,
143562306a36Sopenharmony_ci				    struct cqe *cqe)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
143862306a36Sopenharmony_ci	struct iscsi_task *task;
143962306a36Sopenharmony_ci	struct bnx2i_login_response *login;
144062306a36Sopenharmony_ci	struct iscsi_login_rsp *resp_hdr;
144162306a36Sopenharmony_ci	int pld_len;
144262306a36Sopenharmony_ci	int pad_len;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	login = (struct bnx2i_login_response *) cqe;
144562306a36Sopenharmony_ci	spin_lock(&session->back_lock);
144662306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
144762306a36Sopenharmony_ci				 login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
144862306a36Sopenharmony_ci	if (!task)
144962306a36Sopenharmony_ci		goto done;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
145262306a36Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
145362306a36Sopenharmony_ci	resp_hdr->opcode = login->op_code;
145462306a36Sopenharmony_ci	resp_hdr->flags = login->response_flags;
145562306a36Sopenharmony_ci	resp_hdr->max_version = login->version_max;
145662306a36Sopenharmony_ci	resp_hdr->active_version = login->version_active;
145762306a36Sopenharmony_ci	resp_hdr->hlength = 0;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	hton24(resp_hdr->dlength, login->data_length);
146062306a36Sopenharmony_ci	memcpy(resp_hdr->isid, &login->isid_lo, 6);
146162306a36Sopenharmony_ci	resp_hdr->tsih = cpu_to_be16(login->tsih);
146262306a36Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
146362306a36Sopenharmony_ci	resp_hdr->statsn = cpu_to_be32(login->stat_sn);
146462306a36Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn);
146562306a36Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn);
146662306a36Sopenharmony_ci	resp_hdr->status_class = login->status_class;
146762306a36Sopenharmony_ci	resp_hdr->status_detail = login->status_detail;
146862306a36Sopenharmony_ci	pld_len = login->data_length;
146962306a36Sopenharmony_ci	bnx2i_conn->gen_pdu.resp_wr_ptr =
147062306a36Sopenharmony_ci					bnx2i_conn->gen_pdu.resp_buf + pld_len;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	pad_len = 0;
147362306a36Sopenharmony_ci	if (pld_len & 0x3)
147462306a36Sopenharmony_ci		pad_len = 4 - (pld_len % 4);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	if (pad_len) {
147762306a36Sopenharmony_ci		int i = 0;
147862306a36Sopenharmony_ci		for (i = 0; i < pad_len; i++) {
147962306a36Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
148062306a36Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr++;
148162306a36Sopenharmony_ci		}
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
148562306a36Sopenharmony_ci		bnx2i_conn->gen_pdu.resp_buf,
148662306a36Sopenharmony_ci		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
148762306a36Sopenharmony_cidone:
148862306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
148962306a36Sopenharmony_ci	return 0;
149062306a36Sopenharmony_ci}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci/**
149462306a36Sopenharmony_ci * bnx2i_process_text_resp - this function handles iscsi text response
149562306a36Sopenharmony_ci * @session:	iscsi session pointer
149662306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection pointer
149762306a36Sopenharmony_ci * @cqe:	pointer to newly DMA'ed CQE entry for processing
149862306a36Sopenharmony_ci *
149962306a36Sopenharmony_ci * process iSCSI Text Response CQE&  complete it to open-iscsi user daemon
150062306a36Sopenharmony_ci */
150162306a36Sopenharmony_cistatic int bnx2i_process_text_resp(struct iscsi_session *session,
150262306a36Sopenharmony_ci				   struct bnx2i_conn *bnx2i_conn,
150362306a36Sopenharmony_ci				   struct cqe *cqe)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
150662306a36Sopenharmony_ci	struct iscsi_task *task;
150762306a36Sopenharmony_ci	struct bnx2i_text_response *text;
150862306a36Sopenharmony_ci	struct iscsi_text_rsp *resp_hdr;
150962306a36Sopenharmony_ci	int pld_len;
151062306a36Sopenharmony_ci	int pad_len;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	text = (struct bnx2i_text_response *) cqe;
151362306a36Sopenharmony_ci	spin_lock(&session->back_lock);
151462306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
151562306a36Sopenharmony_ci	if (!task)
151662306a36Sopenharmony_ci		goto done;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	resp_hdr = (struct iscsi_text_rsp *)&bnx2i_conn->gen_pdu.resp_hdr;
151962306a36Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
152062306a36Sopenharmony_ci	resp_hdr->opcode = text->op_code;
152162306a36Sopenharmony_ci	resp_hdr->flags = text->response_flags;
152262306a36Sopenharmony_ci	resp_hdr->hlength = 0;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	hton24(resp_hdr->dlength, text->data_length);
152562306a36Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
152662306a36Sopenharmony_ci	resp_hdr->ttt = cpu_to_be32(text->ttt);
152762306a36Sopenharmony_ci	resp_hdr->statsn = task->hdr->exp_statsn;
152862306a36Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(text->exp_cmd_sn);
152962306a36Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(text->max_cmd_sn);
153062306a36Sopenharmony_ci	pld_len = text->data_length;
153162306a36Sopenharmony_ci	bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf +
153262306a36Sopenharmony_ci					  pld_len;
153362306a36Sopenharmony_ci	pad_len = 0;
153462306a36Sopenharmony_ci	if (pld_len & 0x3)
153562306a36Sopenharmony_ci		pad_len = 4 - (pld_len % 4);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	if (pad_len) {
153862306a36Sopenharmony_ci		int i = 0;
153962306a36Sopenharmony_ci		for (i = 0; i < pad_len; i++) {
154062306a36Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
154162306a36Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr++;
154262306a36Sopenharmony_ci		}
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
154562306a36Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_buf,
154662306a36Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_wr_ptr -
154762306a36Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_buf);
154862306a36Sopenharmony_cidone:
154962306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
155062306a36Sopenharmony_ci	return 0;
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci/**
155562306a36Sopenharmony_ci * bnx2i_process_tmf_resp - this function handles iscsi TMF response
155662306a36Sopenharmony_ci * @session:		iscsi session pointer
155762306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
155862306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
155962306a36Sopenharmony_ci *
156062306a36Sopenharmony_ci * process iSCSI TMF Response CQE and wake up the driver eh thread.
156162306a36Sopenharmony_ci */
156262306a36Sopenharmony_cistatic int bnx2i_process_tmf_resp(struct iscsi_session *session,
156362306a36Sopenharmony_ci				  struct bnx2i_conn *bnx2i_conn,
156462306a36Sopenharmony_ci				  struct cqe *cqe)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
156762306a36Sopenharmony_ci	struct iscsi_task *task;
156862306a36Sopenharmony_ci	struct bnx2i_tmf_response *tmf_cqe;
156962306a36Sopenharmony_ci	struct iscsi_tm_rsp *resp_hdr;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	tmf_cqe = (struct bnx2i_tmf_response *)cqe;
157262306a36Sopenharmony_ci	spin_lock(&session->back_lock);
157362306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
157462306a36Sopenharmony_ci				 tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
157562306a36Sopenharmony_ci	if (!task)
157662306a36Sopenharmony_ci		goto done;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
157962306a36Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
158062306a36Sopenharmony_ci	resp_hdr->opcode = tmf_cqe->op_code;
158162306a36Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn);
158262306a36Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn);
158362306a36Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
158462306a36Sopenharmony_ci	resp_hdr->response = tmf_cqe->response;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
158762306a36Sopenharmony_cidone:
158862306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
158962306a36Sopenharmony_ci	return 0;
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci/**
159362306a36Sopenharmony_ci * bnx2i_process_logout_resp - this function handles iscsi logout response
159462306a36Sopenharmony_ci * @session:		iscsi session pointer
159562306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
159662306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
159762306a36Sopenharmony_ci *
159862306a36Sopenharmony_ci * process iSCSI Logout Response CQE & make function call to
159962306a36Sopenharmony_ci * notify the user daemon.
160062306a36Sopenharmony_ci */
160162306a36Sopenharmony_cistatic int bnx2i_process_logout_resp(struct iscsi_session *session,
160262306a36Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
160362306a36Sopenharmony_ci				     struct cqe *cqe)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
160662306a36Sopenharmony_ci	struct iscsi_task *task;
160762306a36Sopenharmony_ci	struct bnx2i_logout_response *logout;
160862306a36Sopenharmony_ci	struct iscsi_logout_rsp *resp_hdr;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	logout = (struct bnx2i_logout_response *) cqe;
161162306a36Sopenharmony_ci	spin_lock(&session->back_lock);
161262306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
161362306a36Sopenharmony_ci				 logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
161462306a36Sopenharmony_ci	if (!task)
161562306a36Sopenharmony_ci		goto done;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
161862306a36Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
161962306a36Sopenharmony_ci	resp_hdr->opcode = logout->op_code;
162062306a36Sopenharmony_ci	resp_hdr->flags = logout->response;
162162306a36Sopenharmony_ci	resp_hdr->hlength = 0;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
162462306a36Sopenharmony_ci	resp_hdr->statsn = task->hdr->exp_statsn;
162562306a36Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn);
162662306a36Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
162962306a36Sopenharmony_ci	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
163462306a36Sopenharmony_cidone:
163562306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
163662306a36Sopenharmony_ci	return 0;
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci/**
164062306a36Sopenharmony_ci * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE
164162306a36Sopenharmony_ci * @session:		iscsi session pointer
164262306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
164362306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
164462306a36Sopenharmony_ci *
164562306a36Sopenharmony_ci * process iSCSI NOPIN local completion CQE, frees IIT and command structures
164662306a36Sopenharmony_ci */
164762306a36Sopenharmony_cistatic void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
164862306a36Sopenharmony_ci					   struct bnx2i_conn *bnx2i_conn,
164962306a36Sopenharmony_ci					   struct cqe *cqe)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
165262306a36Sopenharmony_ci	struct bnx2i_nop_in_msg *nop_in;
165362306a36Sopenharmony_ci	struct iscsi_task *task;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	nop_in = (struct bnx2i_nop_in_msg *)cqe;
165662306a36Sopenharmony_ci	spin_lock(&session->back_lock);
165762306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
165862306a36Sopenharmony_ci				 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
165962306a36Sopenharmony_ci	if (task)
166062306a36Sopenharmony_ci		__iscsi_put_task(task);
166162306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/**
166562306a36Sopenharmony_ci * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd
166662306a36Sopenharmony_ci * @bnx2i_conn:	iscsi connection
166762306a36Sopenharmony_ci *
166862306a36Sopenharmony_ci * Firmware advances RQ producer index for every unsolicited PDU even if
166962306a36Sopenharmony_ci *	payload data length is '0'. This function makes corresponding
167062306a36Sopenharmony_ci *	adjustments on the driver side to match this f/w behavior
167162306a36Sopenharmony_ci */
167262306a36Sopenharmony_cistatic void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	char dummy_rq_data[2];
167562306a36Sopenharmony_ci	bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1);
167662306a36Sopenharmony_ci	bnx2i_put_rq_buf(bnx2i_conn, 1);
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci/**
168162306a36Sopenharmony_ci * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE
168262306a36Sopenharmony_ci * @session:		iscsi session pointer
168362306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
168462306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
168562306a36Sopenharmony_ci *
168662306a36Sopenharmony_ci * process iSCSI target's proactive iSCSI NOPIN request
168762306a36Sopenharmony_ci */
168862306a36Sopenharmony_cistatic int bnx2i_process_nopin_mesg(struct iscsi_session *session,
168962306a36Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
169062306a36Sopenharmony_ci				     struct cqe *cqe)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
169362306a36Sopenharmony_ci	struct iscsi_task *task;
169462306a36Sopenharmony_ci	struct bnx2i_nop_in_msg *nop_in;
169562306a36Sopenharmony_ci	struct iscsi_nopin *hdr;
169662306a36Sopenharmony_ci	int tgt_async_nop = 0;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	nop_in = (struct bnx2i_nop_in_msg *)cqe;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	spin_lock(&session->back_lock);
170162306a36Sopenharmony_ci	hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
170262306a36Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
170362306a36Sopenharmony_ci	hdr->opcode = nop_in->op_code;
170462306a36Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn);
170562306a36Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
170662306a36Sopenharmony_ci	hdr->ttt = cpu_to_be32(nop_in->ttt);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	if (nop_in->itt == (u16) RESERVED_ITT) {
170962306a36Sopenharmony_ci		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
171062306a36Sopenharmony_ci		hdr->itt = RESERVED_ITT;
171162306a36Sopenharmony_ci		tgt_async_nop = 1;
171262306a36Sopenharmony_ci		goto done;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/* this is a response to one of our nop-outs */
171662306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
171762306a36Sopenharmony_ci			 (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX));
171862306a36Sopenharmony_ci	if (task) {
171962306a36Sopenharmony_ci		hdr->flags = ISCSI_FLAG_CMD_FINAL;
172062306a36Sopenharmony_ci		hdr->itt = task->hdr->itt;
172162306a36Sopenharmony_ci		hdr->ttt = cpu_to_be32(nop_in->ttt);
172262306a36Sopenharmony_ci		memcpy(&hdr->lun, nop_in->lun, 8);
172362306a36Sopenharmony_ci	}
172462306a36Sopenharmony_cidone:
172562306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
172662306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	return tgt_async_nop;
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/**
173362306a36Sopenharmony_ci * bnx2i_process_async_mesg - this function handles iscsi async message
173462306a36Sopenharmony_ci * @session:		iscsi session pointer
173562306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
173662306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
173762306a36Sopenharmony_ci *
173862306a36Sopenharmony_ci * process iSCSI ASYNC Message
173962306a36Sopenharmony_ci */
174062306a36Sopenharmony_cistatic void bnx2i_process_async_mesg(struct iscsi_session *session,
174162306a36Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
174262306a36Sopenharmony_ci				     struct cqe *cqe)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct bnx2i_async_msg *async_cqe;
174562306a36Sopenharmony_ci	struct iscsi_async *resp_hdr;
174662306a36Sopenharmony_ci	u8 async_event;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	async_cqe = (struct bnx2i_async_msg *)cqe;
175162306a36Sopenharmony_ci	async_event = async_cqe->async_event;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) {
175462306a36Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
175562306a36Sopenharmony_ci				  "async: scsi events not supported\n");
175662306a36Sopenharmony_ci		return;
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	spin_lock(&session->back_lock);
176062306a36Sopenharmony_ci	resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
176162306a36Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
176262306a36Sopenharmony_ci	resp_hdr->opcode = async_cqe->op_code;
176362306a36Sopenharmony_ci	resp_hdr->flags = 0x80;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	memcpy(&resp_hdr->lun, async_cqe->lun, 8);
176662306a36Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
176762306a36Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	resp_hdr->async_event = async_cqe->async_event;
177062306a36Sopenharmony_ci	resp_hdr->async_vcode = async_cqe->async_vcode;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	resp_hdr->param1 = cpu_to_be16(async_cqe->param1);
177362306a36Sopenharmony_ci	resp_hdr->param2 = cpu_to_be16(async_cqe->param2);
177462306a36Sopenharmony_ci	resp_hdr->param3 = cpu_to_be16(async_cqe->param3);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
177762306a36Sopenharmony_ci			     (struct iscsi_hdr *)resp_hdr, NULL, 0);
177862306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci/**
178362306a36Sopenharmony_ci * bnx2i_process_reject_mesg - process iscsi reject pdu
178462306a36Sopenharmony_ci * @session:		iscsi session pointer
178562306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
178662306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
178762306a36Sopenharmony_ci *
178862306a36Sopenharmony_ci * process iSCSI REJECT message
178962306a36Sopenharmony_ci */
179062306a36Sopenharmony_cistatic void bnx2i_process_reject_mesg(struct iscsi_session *session,
179162306a36Sopenharmony_ci				      struct bnx2i_conn *bnx2i_conn,
179262306a36Sopenharmony_ci				      struct cqe *cqe)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
179562306a36Sopenharmony_ci	struct bnx2i_reject_msg *reject;
179662306a36Sopenharmony_ci	struct iscsi_reject *hdr;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	reject = (struct bnx2i_reject_msg *) cqe;
179962306a36Sopenharmony_ci	if (reject->data_length) {
180062306a36Sopenharmony_ci		bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length);
180162306a36Sopenharmony_ci		bnx2i_put_rq_buf(bnx2i_conn, 1);
180262306a36Sopenharmony_ci	} else
180362306a36Sopenharmony_ci		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	spin_lock(&session->back_lock);
180662306a36Sopenharmony_ci	hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
180762306a36Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
180862306a36Sopenharmony_ci	hdr->opcode = reject->op_code;
180962306a36Sopenharmony_ci	hdr->reason = reject->reason;
181062306a36Sopenharmony_ci	hton24(hdr->dlength, reject->data_length);
181162306a36Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn);
181262306a36Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn);
181362306a36Sopenharmony_ci	hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
181462306a36Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
181562306a36Sopenharmony_ci			     reject->data_length);
181662306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
181762306a36Sopenharmony_ci}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci/**
182062306a36Sopenharmony_ci * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion
182162306a36Sopenharmony_ci * @session:		iscsi session pointer
182262306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
182362306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
182462306a36Sopenharmony_ci *
182562306a36Sopenharmony_ci * process command cleanup response CQE during conn shutdown or error recovery
182662306a36Sopenharmony_ci */
182762306a36Sopenharmony_cistatic void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
182862306a36Sopenharmony_ci					   struct bnx2i_conn *bnx2i_conn,
182962306a36Sopenharmony_ci					   struct cqe *cqe)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	struct bnx2i_cleanup_response *cmd_clean_rsp;
183262306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
183362306a36Sopenharmony_ci	struct iscsi_task *task;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
183662306a36Sopenharmony_ci	spin_lock(&session->back_lock);
183762306a36Sopenharmony_ci	task = iscsi_itt_to_task(conn,
183862306a36Sopenharmony_ci			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
183962306a36Sopenharmony_ci	if (!task)
184062306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
184162306a36Sopenharmony_ci			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
184262306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
184362306a36Sopenharmony_ci	complete(&bnx2i_conn->cmd_cleanup_cmpl);
184462306a36Sopenharmony_ci}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci/**
184862306a36Sopenharmony_ci * bnx2i_percpu_io_thread - thread per cpu for ios
184962306a36Sopenharmony_ci *
185062306a36Sopenharmony_ci * @arg:	ptr to bnx2i_percpu_info structure
185162306a36Sopenharmony_ci */
185262306a36Sopenharmony_ciint bnx2i_percpu_io_thread(void *arg)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	struct bnx2i_percpu_s *p = arg;
185562306a36Sopenharmony_ci	struct bnx2i_work *work, *tmp;
185662306a36Sopenharmony_ci	LIST_HEAD(work_list);
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	set_user_nice(current, MIN_NICE);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	while (!kthread_should_stop()) {
186162306a36Sopenharmony_ci		spin_lock_bh(&p->p_work_lock);
186262306a36Sopenharmony_ci		while (!list_empty(&p->work_list)) {
186362306a36Sopenharmony_ci			list_splice_init(&p->work_list, &work_list);
186462306a36Sopenharmony_ci			spin_unlock_bh(&p->p_work_lock);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci			list_for_each_entry_safe(work, tmp, &work_list, list) {
186762306a36Sopenharmony_ci				list_del_init(&work->list);
186862306a36Sopenharmony_ci				/* work allocated in the bh, freed here */
186962306a36Sopenharmony_ci				bnx2i_process_scsi_cmd_resp(work->session,
187062306a36Sopenharmony_ci							    work->bnx2i_conn,
187162306a36Sopenharmony_ci							    &work->cqe);
187262306a36Sopenharmony_ci				atomic_dec(&work->bnx2i_conn->work_cnt);
187362306a36Sopenharmony_ci				kfree(work);
187462306a36Sopenharmony_ci			}
187562306a36Sopenharmony_ci			spin_lock_bh(&p->p_work_lock);
187662306a36Sopenharmony_ci		}
187762306a36Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
187862306a36Sopenharmony_ci		spin_unlock_bh(&p->p_work_lock);
187962306a36Sopenharmony_ci		schedule();
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci	__set_current_state(TASK_RUNNING);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	return 0;
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci/**
188862306a36Sopenharmony_ci * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread
188962306a36Sopenharmony_ci * @session:		iscsi session
189062306a36Sopenharmony_ci * @bnx2i_conn:		bnx2i connection
189162306a36Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
189262306a36Sopenharmony_ci *
189362306a36Sopenharmony_ci * this function is called by generic KCQ handler to queue all pending cmd
189462306a36Sopenharmony_ci * completion CQEs
189562306a36Sopenharmony_ci *
189662306a36Sopenharmony_ci * The implementation is to queue the cmd response based on the
189762306a36Sopenharmony_ci * last recorded command for the given connection.  The
189862306a36Sopenharmony_ci * cpu_id gets recorded upon task_xmit.  No out-of-order completion!
189962306a36Sopenharmony_ci */
190062306a36Sopenharmony_cistatic int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
190162306a36Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
190262306a36Sopenharmony_ci				     struct bnx2i_nop_in_msg *cqe)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	struct bnx2i_work *bnx2i_work = NULL;
190562306a36Sopenharmony_ci	struct bnx2i_percpu_s *p = NULL;
190662306a36Sopenharmony_ci	struct iscsi_task *task;
190762306a36Sopenharmony_ci	struct scsi_cmnd *sc;
190862306a36Sopenharmony_ci	int rc = 0;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	spin_lock(&session->back_lock);
191162306a36Sopenharmony_ci	task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
191262306a36Sopenharmony_ci				 cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
191362306a36Sopenharmony_ci	if (!task || !task->sc) {
191462306a36Sopenharmony_ci		spin_unlock(&session->back_lock);
191562306a36Sopenharmony_ci		return -EINVAL;
191662306a36Sopenharmony_ci	}
191762306a36Sopenharmony_ci	sc = task->sc;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	spin_unlock(&session->back_lock);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	p = &per_cpu(bnx2i_percpu, blk_mq_rq_cpu(scsi_cmd_to_rq(sc)));
192262306a36Sopenharmony_ci	spin_lock(&p->p_work_lock);
192362306a36Sopenharmony_ci	if (unlikely(!p->iothread)) {
192462306a36Sopenharmony_ci		rc = -EINVAL;
192562306a36Sopenharmony_ci		goto err;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci	/* Alloc and copy to the cqe */
192862306a36Sopenharmony_ci	bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC);
192962306a36Sopenharmony_ci	if (bnx2i_work) {
193062306a36Sopenharmony_ci		INIT_LIST_HEAD(&bnx2i_work->list);
193162306a36Sopenharmony_ci		bnx2i_work->session = session;
193262306a36Sopenharmony_ci		bnx2i_work->bnx2i_conn = bnx2i_conn;
193362306a36Sopenharmony_ci		memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe));
193462306a36Sopenharmony_ci		list_add_tail(&bnx2i_work->list, &p->work_list);
193562306a36Sopenharmony_ci		atomic_inc(&bnx2i_conn->work_cnt);
193662306a36Sopenharmony_ci		wake_up_process(p->iothread);
193762306a36Sopenharmony_ci		spin_unlock(&p->p_work_lock);
193862306a36Sopenharmony_ci		goto done;
193962306a36Sopenharmony_ci	} else
194062306a36Sopenharmony_ci		rc = -ENOMEM;
194162306a36Sopenharmony_cierr:
194262306a36Sopenharmony_ci	spin_unlock(&p->p_work_lock);
194362306a36Sopenharmony_ci	bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe);
194462306a36Sopenharmony_cidone:
194562306a36Sopenharmony_ci	return rc;
194662306a36Sopenharmony_ci}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci/**
195062306a36Sopenharmony_ci * bnx2i_process_new_cqes - process newly DMA'ed CQE's
195162306a36Sopenharmony_ci * @bnx2i_conn:		bnx2i connection
195262306a36Sopenharmony_ci *
195362306a36Sopenharmony_ci * this function is called by generic KCQ handler to process all pending CQE's
195462306a36Sopenharmony_ci */
195562306a36Sopenharmony_cistatic int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
195862306a36Sopenharmony_ci	struct iscsi_session *session = conn->session;
195962306a36Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
196062306a36Sopenharmony_ci	struct qp_info *qp;
196162306a36Sopenharmony_ci	struct bnx2i_nop_in_msg *nopin;
196262306a36Sopenharmony_ci	int tgt_async_msg;
196362306a36Sopenharmony_ci	int cqe_cnt = 0;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (bnx2i_conn->ep == NULL)
196662306a36Sopenharmony_ci		return 0;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	qp = &bnx2i_conn->ep->qp;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (!qp->cq_virt) {
197162306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!",
197262306a36Sopenharmony_ci		       hba->netdev->name);
197362306a36Sopenharmony_ci		goto out;
197462306a36Sopenharmony_ci	}
197562306a36Sopenharmony_ci	while (1) {
197662306a36Sopenharmony_ci		nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
197762306a36Sopenharmony_ci		if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
197862306a36Sopenharmony_ci			break;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		if (unlikely(test_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags))) {
198162306a36Sopenharmony_ci			if (nopin->op_code == ISCSI_OP_NOOP_IN &&
198262306a36Sopenharmony_ci			    nopin->itt == (u16) RESERVED_ITT) {
198362306a36Sopenharmony_ci				printk(KERN_ALERT "bnx2i: Unsolicited "
198462306a36Sopenharmony_ci				       "NOP-In detected for suspended "
198562306a36Sopenharmony_ci				       "connection dev=%s!\n",
198662306a36Sopenharmony_ci				       hba->netdev->name);
198762306a36Sopenharmony_ci				bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
198862306a36Sopenharmony_ci				goto cqe_out;
198962306a36Sopenharmony_ci			}
199062306a36Sopenharmony_ci			break;
199162306a36Sopenharmony_ci		}
199262306a36Sopenharmony_ci		tgt_async_msg = 0;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci		switch (nopin->op_code) {
199562306a36Sopenharmony_ci		case ISCSI_OP_SCSI_CMD_RSP:
199662306a36Sopenharmony_ci		case ISCSI_OP_SCSI_DATA_IN:
199762306a36Sopenharmony_ci			/* Run the kthread engine only for data cmds
199862306a36Sopenharmony_ci			   All other cmds will be completed in this bh! */
199962306a36Sopenharmony_ci			bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin);
200062306a36Sopenharmony_ci			goto done;
200162306a36Sopenharmony_ci		case ISCSI_OP_LOGIN_RSP:
200262306a36Sopenharmony_ci			bnx2i_process_login_resp(session, bnx2i_conn,
200362306a36Sopenharmony_ci						 qp->cq_cons_qe);
200462306a36Sopenharmony_ci			break;
200562306a36Sopenharmony_ci		case ISCSI_OP_SCSI_TMFUNC_RSP:
200662306a36Sopenharmony_ci			bnx2i_process_tmf_resp(session, bnx2i_conn,
200762306a36Sopenharmony_ci					       qp->cq_cons_qe);
200862306a36Sopenharmony_ci			break;
200962306a36Sopenharmony_ci		case ISCSI_OP_TEXT_RSP:
201062306a36Sopenharmony_ci			bnx2i_process_text_resp(session, bnx2i_conn,
201162306a36Sopenharmony_ci						qp->cq_cons_qe);
201262306a36Sopenharmony_ci			break;
201362306a36Sopenharmony_ci		case ISCSI_OP_LOGOUT_RSP:
201462306a36Sopenharmony_ci			bnx2i_process_logout_resp(session, bnx2i_conn,
201562306a36Sopenharmony_ci						  qp->cq_cons_qe);
201662306a36Sopenharmony_ci			break;
201762306a36Sopenharmony_ci		case ISCSI_OP_NOOP_IN:
201862306a36Sopenharmony_ci			if (bnx2i_process_nopin_mesg(session, bnx2i_conn,
201962306a36Sopenharmony_ci						     qp->cq_cons_qe))
202062306a36Sopenharmony_ci				tgt_async_msg = 1;
202162306a36Sopenharmony_ci			break;
202262306a36Sopenharmony_ci		case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION:
202362306a36Sopenharmony_ci			bnx2i_process_nopin_local_cmpl(session, bnx2i_conn,
202462306a36Sopenharmony_ci						       qp->cq_cons_qe);
202562306a36Sopenharmony_ci			break;
202662306a36Sopenharmony_ci		case ISCSI_OP_ASYNC_EVENT:
202762306a36Sopenharmony_ci			bnx2i_process_async_mesg(session, bnx2i_conn,
202862306a36Sopenharmony_ci						 qp->cq_cons_qe);
202962306a36Sopenharmony_ci			tgt_async_msg = 1;
203062306a36Sopenharmony_ci			break;
203162306a36Sopenharmony_ci		case ISCSI_OP_REJECT:
203262306a36Sopenharmony_ci			bnx2i_process_reject_mesg(session, bnx2i_conn,
203362306a36Sopenharmony_ci						  qp->cq_cons_qe);
203462306a36Sopenharmony_ci			break;
203562306a36Sopenharmony_ci		case ISCSI_OPCODE_CLEANUP_RESPONSE:
203662306a36Sopenharmony_ci			bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn,
203762306a36Sopenharmony_ci						       qp->cq_cons_qe);
203862306a36Sopenharmony_ci			break;
203962306a36Sopenharmony_ci		default:
204062306a36Sopenharmony_ci			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
204162306a36Sopenharmony_ci					  nopin->op_code);
204262306a36Sopenharmony_ci		}
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus, 1);
204562306a36Sopenharmony_ci		ADD_STATS_64(hba, rx_bytes, nopin->data_length);
204662306a36Sopenharmony_cidone:
204762306a36Sopenharmony_ci		if (!tgt_async_msg) {
204862306a36Sopenharmony_ci			if (!atomic_read(&bnx2i_conn->ep->num_active_cmds))
204962306a36Sopenharmony_ci				printk(KERN_ALERT "bnx2i (%s): no active cmd! "
205062306a36Sopenharmony_ci				       "op 0x%x\n",
205162306a36Sopenharmony_ci				       hba->netdev->name,
205262306a36Sopenharmony_ci				       nopin->op_code);
205362306a36Sopenharmony_ci			else
205462306a36Sopenharmony_ci				atomic_dec(&bnx2i_conn->ep->num_active_cmds);
205562306a36Sopenharmony_ci		}
205662306a36Sopenharmony_cicqe_out:
205762306a36Sopenharmony_ci		/* clear out in production version only, till beta keep opcode
205862306a36Sopenharmony_ci		 * field intact, will be helpful in debugging (context dump)
205962306a36Sopenharmony_ci		 * nopin->op_code = 0;
206062306a36Sopenharmony_ci		 */
206162306a36Sopenharmony_ci		cqe_cnt++;
206262306a36Sopenharmony_ci		qp->cqe_exp_seq_sn++;
206362306a36Sopenharmony_ci		if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
206462306a36Sopenharmony_ci			qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci		if (qp->cq_cons_qe == qp->cq_last_qe) {
206762306a36Sopenharmony_ci			qp->cq_cons_qe = qp->cq_first_qe;
206862306a36Sopenharmony_ci			qp->cq_cons_idx = 0;
206962306a36Sopenharmony_ci		} else {
207062306a36Sopenharmony_ci			qp->cq_cons_qe++;
207162306a36Sopenharmony_ci			qp->cq_cons_idx++;
207262306a36Sopenharmony_ci		}
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ciout:
207562306a36Sopenharmony_ci	return cqe_cnt;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci/**
207962306a36Sopenharmony_ci * bnx2i_fastpath_notification - process global event queue (KCQ)
208062306a36Sopenharmony_ci * @hba:		adapter structure pointer
208162306a36Sopenharmony_ci * @new_cqe_kcqe:	pointer to newly DMA'ed KCQE entry
208262306a36Sopenharmony_ci *
208362306a36Sopenharmony_ci * Fast path event notification handler, KCQ entry carries context id
208462306a36Sopenharmony_ci *	of the connection that has 1 or more pending CQ entries
208562306a36Sopenharmony_ci */
208662306a36Sopenharmony_cistatic void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
208762306a36Sopenharmony_ci					struct iscsi_kcqe *new_cqe_kcqe)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
209062306a36Sopenharmony_ci	u32 iscsi_cid;
209162306a36Sopenharmony_ci	int nxt_idx;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
209462306a36Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	if (!bnx2i_conn) {
209762306a36Sopenharmony_ci		printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
209862306a36Sopenharmony_ci		return;
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci	if (!bnx2i_conn->ep) {
210162306a36Sopenharmony_ci		printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
210262306a36Sopenharmony_ci		return;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	bnx2i_process_new_cqes(bnx2i_conn);
210662306a36Sopenharmony_ci	nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep,
210762306a36Sopenharmony_ci						CNIC_ARM_CQE_FP);
210862306a36Sopenharmony_ci	if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn))
210962306a36Sopenharmony_ci		bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
211062306a36Sopenharmony_ci}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci/**
211462306a36Sopenharmony_ci * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE
211562306a36Sopenharmony_ci * @hba:		adapter structure pointer
211662306a36Sopenharmony_ci * @update_kcqe:	kcqe pointer
211762306a36Sopenharmony_ci *
211862306a36Sopenharmony_ci * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration
211962306a36Sopenharmony_ci */
212062306a36Sopenharmony_cistatic void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba,
212162306a36Sopenharmony_ci					   struct iscsi_kcqe *update_kcqe)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	struct bnx2i_conn *conn;
212462306a36Sopenharmony_ci	u32 iscsi_cid;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	iscsi_cid = update_kcqe->iscsi_conn_id;
212762306a36Sopenharmony_ci	conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	if (!conn) {
213062306a36Sopenharmony_ci		printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid);
213162306a36Sopenharmony_ci		return;
213262306a36Sopenharmony_ci	}
213362306a36Sopenharmony_ci	if (!conn->ep) {
213462306a36Sopenharmony_ci		printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid);
213562306a36Sopenharmony_ci		return;
213662306a36Sopenharmony_ci	}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (update_kcqe->completion_status) {
213962306a36Sopenharmony_ci		printk(KERN_ALERT "request failed cid %x\n", iscsi_cid);
214062306a36Sopenharmony_ci		conn->ep->state = EP_STATE_ULP_UPDATE_FAILED;
214162306a36Sopenharmony_ci	} else
214262306a36Sopenharmony_ci		conn->ep->state = EP_STATE_ULP_UPDATE_COMPL;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	wake_up_interruptible(&conn->ep->ofld_wait);
214562306a36Sopenharmony_ci}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci/**
214962306a36Sopenharmony_ci * bnx2i_recovery_que_add_conn - add connection to recovery queue
215062306a36Sopenharmony_ci * @hba:		adapter structure pointer
215162306a36Sopenharmony_ci * @bnx2i_conn:		iscsi connection
215262306a36Sopenharmony_ci *
215362306a36Sopenharmony_ci * Add connection to recovery queue and schedule adapter eh worker
215462306a36Sopenharmony_ci */
215562306a36Sopenharmony_cistatic void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba,
215662306a36Sopenharmony_ci					struct bnx2i_conn *bnx2i_conn)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data,
215962306a36Sopenharmony_ci			   ISCSI_ERR_CONN_FAILED);
216062306a36Sopenharmony_ci}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci/**
216462306a36Sopenharmony_ci * bnx2i_process_tcp_error - process error notification on a given connection
216562306a36Sopenharmony_ci *
216662306a36Sopenharmony_ci * @hba: 		adapter structure pointer
216762306a36Sopenharmony_ci * @tcp_err: 		tcp error kcqe pointer
216862306a36Sopenharmony_ci *
216962306a36Sopenharmony_ci * handles tcp level error notifications from FW.
217062306a36Sopenharmony_ci */
217162306a36Sopenharmony_cistatic void bnx2i_process_tcp_error(struct bnx2i_hba *hba,
217262306a36Sopenharmony_ci				    struct iscsi_kcqe *tcp_err)
217362306a36Sopenharmony_ci{
217462306a36Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
217562306a36Sopenharmony_ci	u32 iscsi_cid;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	iscsi_cid = tcp_err->iscsi_conn_id;
217862306a36Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (!bnx2i_conn) {
218162306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
218262306a36Sopenharmony_ci		return;
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n",
218662306a36Sopenharmony_ci			  iscsi_cid, tcp_err->completion_status);
218762306a36Sopenharmony_ci	bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
218862306a36Sopenharmony_ci}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci/**
219262306a36Sopenharmony_ci * bnx2i_process_iscsi_error - process error notification on a given connection
219362306a36Sopenharmony_ci * @hba:		adapter structure pointer
219462306a36Sopenharmony_ci * @iscsi_err:		iscsi error kcqe pointer
219562306a36Sopenharmony_ci *
219662306a36Sopenharmony_ci * handles iscsi error notifications from the FW. Firmware based in initial
219762306a36Sopenharmony_ci *	handshake classifies iscsi protocol / TCP rfc violation into either
219862306a36Sopenharmony_ci *	warning or error indications. If indication is of "Error" type, driver
219962306a36Sopenharmony_ci *	will initiate session recovery for that connection/session. For
220062306a36Sopenharmony_ci *	"Warning" type indication, driver will put out a system log message
220162306a36Sopenharmony_ci *	(there will be only one message for each type for the life of the
220262306a36Sopenharmony_ci *	session, this is to avoid un-necessarily overloading the system)
220362306a36Sopenharmony_ci */
220462306a36Sopenharmony_cistatic void bnx2i_process_iscsi_error(struct bnx2i_hba *hba,
220562306a36Sopenharmony_ci				      struct iscsi_kcqe *iscsi_err)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
220862306a36Sopenharmony_ci	u32 iscsi_cid;
220962306a36Sopenharmony_ci	const char *additional_notice = "";
221062306a36Sopenharmony_ci	const char *message;
221162306a36Sopenharmony_ci	int need_recovery;
221262306a36Sopenharmony_ci	u64 err_mask64;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	iscsi_cid = iscsi_err->iscsi_conn_id;
221562306a36Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
221662306a36Sopenharmony_ci	if (!bnx2i_conn) {
221762306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
221862306a36Sopenharmony_ci		return;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	err_mask64 = (0x1ULL << iscsi_err->completion_status);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	if (err_mask64 & iscsi_error_mask) {
222462306a36Sopenharmony_ci		need_recovery = 0;
222562306a36Sopenharmony_ci		message = "iscsi_warning";
222662306a36Sopenharmony_ci	} else {
222762306a36Sopenharmony_ci		need_recovery = 1;
222862306a36Sopenharmony_ci		message = "iscsi_error";
222962306a36Sopenharmony_ci	}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	switch (iscsi_err->completion_status) {
223262306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR:
223362306a36Sopenharmony_ci		additional_notice = "hdr digest err";
223462306a36Sopenharmony_ci		break;
223562306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR:
223662306a36Sopenharmony_ci		additional_notice = "data digest err";
223762306a36Sopenharmony_ci		break;
223862306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE:
223962306a36Sopenharmony_ci		additional_notice = "wrong opcode rcvd";
224062306a36Sopenharmony_ci		break;
224162306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN:
224262306a36Sopenharmony_ci		additional_notice = "AHS len > 0 rcvd";
224362306a36Sopenharmony_ci		break;
224462306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT:
224562306a36Sopenharmony_ci		additional_notice = "invalid ITT rcvd";
224662306a36Sopenharmony_ci		break;
224762306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN:
224862306a36Sopenharmony_ci		additional_notice = "wrong StatSN rcvd";
224962306a36Sopenharmony_ci		break;
225062306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN:
225162306a36Sopenharmony_ci		additional_notice = "wrong DataSN rcvd";
225262306a36Sopenharmony_ci		break;
225362306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T:
225462306a36Sopenharmony_ci		additional_notice = "pend R2T violation";
225562306a36Sopenharmony_ci		break;
225662306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0:
225762306a36Sopenharmony_ci		additional_notice = "ERL0, UO";
225862306a36Sopenharmony_ci		break;
225962306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1:
226062306a36Sopenharmony_ci		additional_notice = "ERL0, U1";
226162306a36Sopenharmony_ci		break;
226262306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2:
226362306a36Sopenharmony_ci		additional_notice = "ERL0, U2";
226462306a36Sopenharmony_ci		break;
226562306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3:
226662306a36Sopenharmony_ci		additional_notice = "ERL0, U3";
226762306a36Sopenharmony_ci		break;
226862306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4:
226962306a36Sopenharmony_ci		additional_notice = "ERL0, U4";
227062306a36Sopenharmony_ci		break;
227162306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5:
227262306a36Sopenharmony_ci		additional_notice = "ERL0, U5";
227362306a36Sopenharmony_ci		break;
227462306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6:
227562306a36Sopenharmony_ci		additional_notice = "ERL0, U6";
227662306a36Sopenharmony_ci		break;
227762306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN:
227862306a36Sopenharmony_ci		additional_notice = "invalid resi len";
227962306a36Sopenharmony_ci		break;
228062306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN:
228162306a36Sopenharmony_ci		additional_notice = "MRDSL violation";
228262306a36Sopenharmony_ci		break;
228362306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO:
228462306a36Sopenharmony_ci		additional_notice = "F-bit not set";
228562306a36Sopenharmony_ci		break;
228662306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV:
228762306a36Sopenharmony_ci		additional_notice = "invalid TTT";
228862306a36Sopenharmony_ci		break;
228962306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN:
229062306a36Sopenharmony_ci		additional_notice = "invalid DataSN";
229162306a36Sopenharmony_ci		break;
229262306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN:
229362306a36Sopenharmony_ci		additional_notice = "burst len violation";
229462306a36Sopenharmony_ci		break;
229562306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF:
229662306a36Sopenharmony_ci		additional_notice = "buf offset violation";
229762306a36Sopenharmony_ci		break;
229862306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN:
229962306a36Sopenharmony_ci		additional_notice = "invalid LUN field";
230062306a36Sopenharmony_ci		break;
230162306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN:
230262306a36Sopenharmony_ci		additional_notice = "invalid R2TSN field";
230362306a36Sopenharmony_ci		break;
230462306a36Sopenharmony_ci#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0 	\
230562306a36Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0
230662306a36Sopenharmony_ci	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0:
230762306a36Sopenharmony_ci		additional_notice = "invalid cmd len1";
230862306a36Sopenharmony_ci		break;
230962306a36Sopenharmony_ci#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1 	\
231062306a36Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1
231162306a36Sopenharmony_ci	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1:
231262306a36Sopenharmony_ci		additional_notice = "invalid cmd len2";
231362306a36Sopenharmony_ci		break;
231462306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED:
231562306a36Sopenharmony_ci		additional_notice = "pend r2t exceeds MaxOutstandingR2T value";
231662306a36Sopenharmony_ci		break;
231762306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV:
231862306a36Sopenharmony_ci		additional_notice = "TTT is rsvd";
231962306a36Sopenharmony_ci		break;
232062306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN:
232162306a36Sopenharmony_ci		additional_notice = "MBL violation";
232262306a36Sopenharmony_ci		break;
232362306a36Sopenharmony_ci#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO 	\
232462306a36Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO
232562306a36Sopenharmony_ci	case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO:
232662306a36Sopenharmony_ci		additional_notice = "data seg len != 0";
232762306a36Sopenharmony_ci		break;
232862306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN:
232962306a36Sopenharmony_ci		additional_notice = "reject pdu len error";
233062306a36Sopenharmony_ci		break;
233162306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN:
233262306a36Sopenharmony_ci		additional_notice = "async pdu len error";
233362306a36Sopenharmony_ci		break;
233462306a36Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN:
233562306a36Sopenharmony_ci		additional_notice = "nopin pdu len error";
233662306a36Sopenharmony_ci		break;
233762306a36Sopenharmony_ci#define BNX2_ERR_PEND_R2T_IN_CLEANUP			\
233862306a36Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP
233962306a36Sopenharmony_ci	case BNX2_ERR_PEND_R2T_IN_CLEANUP:
234062306a36Sopenharmony_ci		additional_notice = "pend r2t in cleanup";
234162306a36Sopenharmony_ci		break;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT:
234462306a36Sopenharmony_ci		additional_notice = "IP fragments rcvd";
234562306a36Sopenharmony_ci		break;
234662306a36Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS:
234762306a36Sopenharmony_ci		additional_notice = "IP options error";
234862306a36Sopenharmony_ci		break;
234962306a36Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG:
235062306a36Sopenharmony_ci		additional_notice = "urgent flag error";
235162306a36Sopenharmony_ci		break;
235262306a36Sopenharmony_ci	default:
235362306a36Sopenharmony_ci		printk(KERN_ALERT "iscsi_err - unknown err %x\n",
235462306a36Sopenharmony_ci				  iscsi_err->completion_status);
235562306a36Sopenharmony_ci	}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	if (need_recovery) {
235862306a36Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT,
235962306a36Sopenharmony_ci				  bnx2i_conn->cls_conn->dd_data,
236062306a36Sopenharmony_ci				  "bnx2i: %s - %s\n",
236162306a36Sopenharmony_ci				  message, additional_notice);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT,
236462306a36Sopenharmony_ci				  bnx2i_conn->cls_conn->dd_data,
236562306a36Sopenharmony_ci				  "conn_err - hostno %d conn %p, "
236662306a36Sopenharmony_ci				  "iscsi_cid %x cid %x\n",
236762306a36Sopenharmony_ci				  bnx2i_conn->hba->shost->host_no,
236862306a36Sopenharmony_ci				  bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid,
236962306a36Sopenharmony_ci				  bnx2i_conn->ep->ep_cid);
237062306a36Sopenharmony_ci		bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
237162306a36Sopenharmony_ci	} else
237262306a36Sopenharmony_ci		if (!test_and_set_bit(iscsi_err->completion_status,
237362306a36Sopenharmony_ci				      (void *) &bnx2i_conn->violation_notified))
237462306a36Sopenharmony_ci			iscsi_conn_printk(KERN_ALERT,
237562306a36Sopenharmony_ci					  bnx2i_conn->cls_conn->dd_data,
237662306a36Sopenharmony_ci					  "bnx2i: %s - %s\n",
237762306a36Sopenharmony_ci					  message, additional_notice);
237862306a36Sopenharmony_ci}
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci/**
238262306a36Sopenharmony_ci * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion
238362306a36Sopenharmony_ci * @hba:		adapter structure pointer
238462306a36Sopenharmony_ci * @conn_destroy:	conn destroy kcqe pointer
238562306a36Sopenharmony_ci *
238662306a36Sopenharmony_ci * handles connection destroy completion request.
238762306a36Sopenharmony_ci */
238862306a36Sopenharmony_cistatic void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
238962306a36Sopenharmony_ci					    struct iscsi_kcqe *conn_destroy)
239062306a36Sopenharmony_ci{
239162306a36Sopenharmony_ci	struct bnx2i_endpoint *ep;
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id);
239462306a36Sopenharmony_ci	if (!ep) {
239562306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending "
239662306a36Sopenharmony_ci				  "offload request, unexpected completion\n");
239762306a36Sopenharmony_ci		return;
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	if (hba != ep->hba) {
240162306a36Sopenharmony_ci		printk(KERN_ALERT "conn destroy- error hba mismatch\n");
240262306a36Sopenharmony_ci		return;
240362306a36Sopenharmony_ci	}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	if (conn_destroy->completion_status) {
240662306a36Sopenharmony_ci		printk(KERN_ALERT "conn_destroy_cmpl: op failed\n");
240762306a36Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_FAILED;
240862306a36Sopenharmony_ci	} else
240962306a36Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_CMPL;
241062306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
241162306a36Sopenharmony_ci}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci/**
241562306a36Sopenharmony_ci * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion
241662306a36Sopenharmony_ci * @hba:		adapter structure pointer
241762306a36Sopenharmony_ci * @ofld_kcqe:		conn offload kcqe pointer
241862306a36Sopenharmony_ci *
241962306a36Sopenharmony_ci * handles initial connection offload completion, ep_connect() thread is
242062306a36Sopenharmony_ci *	woken-up to continue with LLP connect process
242162306a36Sopenharmony_ci */
242262306a36Sopenharmony_cistatic void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
242362306a36Sopenharmony_ci				    struct iscsi_kcqe *ofld_kcqe)
242462306a36Sopenharmony_ci{
242562306a36Sopenharmony_ci	u32 cid_addr;
242662306a36Sopenharmony_ci	struct bnx2i_endpoint *ep;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id);
242962306a36Sopenharmony_ci	if (!ep) {
243062306a36Sopenharmony_ci		printk(KERN_ALERT "ofld_cmpl: no pend offload request\n");
243162306a36Sopenharmony_ci		return;
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	if (hba != ep->hba) {
243562306a36Sopenharmony_ci		printk(KERN_ALERT "ofld_cmpl: error hba mismatch\n");
243662306a36Sopenharmony_ci		return;
243762306a36Sopenharmony_ci	}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	if (ofld_kcqe->completion_status) {
244062306a36Sopenharmony_ci		ep->state = EP_STATE_OFLD_FAILED;
244162306a36Sopenharmony_ci		if (ofld_kcqe->completion_status ==
244262306a36Sopenharmony_ci		    ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
244362306a36Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable "
244462306a36Sopenharmony_ci				"to allocate iSCSI context resources\n",
244562306a36Sopenharmony_ci				hba->netdev->name);
244662306a36Sopenharmony_ci		else if (ofld_kcqe->completion_status ==
244762306a36Sopenharmony_ci			 ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE)
244862306a36Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
244962306a36Sopenharmony_ci				"opcode\n", hba->netdev->name);
245062306a36Sopenharmony_ci		else if (ofld_kcqe->completion_status ==
245162306a36Sopenharmony_ci			 ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
245262306a36Sopenharmony_ci			/* error status code valid only for 5771x chipset */
245362306a36Sopenharmony_ci			ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
245462306a36Sopenharmony_ci		else
245562306a36Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
245662306a36Sopenharmony_ci				"error code %d\n", hba->netdev->name,
245762306a36Sopenharmony_ci				ofld_kcqe->completion_status);
245862306a36Sopenharmony_ci	} else {
245962306a36Sopenharmony_ci		ep->state = EP_STATE_OFLD_COMPL;
246062306a36Sopenharmony_ci		cid_addr = ofld_kcqe->iscsi_conn_context_id;
246162306a36Sopenharmony_ci		ep->ep_cid = cid_addr;
246262306a36Sopenharmony_ci		ep->qp.ctx_base = NULL;
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
246562306a36Sopenharmony_ci}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci/**
246862306a36Sopenharmony_ci * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE
246962306a36Sopenharmony_ci * @context:		adapter structure pointer
247062306a36Sopenharmony_ci * @kcqe:		kcqe pointer
247162306a36Sopenharmony_ci * @num_cqe:		number of kcqes to process
247262306a36Sopenharmony_ci *
247362306a36Sopenharmony_ci * Generic KCQ event handler/dispatcher
247462306a36Sopenharmony_ci */
247562306a36Sopenharmony_cistatic void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[],
247662306a36Sopenharmony_ci				u32 num_cqe)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	struct bnx2i_hba *hba = context;
247962306a36Sopenharmony_ci	int i = 0;
248062306a36Sopenharmony_ci	struct iscsi_kcqe *ikcqe = NULL;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	while (i < num_cqe) {
248362306a36Sopenharmony_ci		ikcqe = (struct iscsi_kcqe *) kcqe[i++];
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci		if (ikcqe->op_code ==
248662306a36Sopenharmony_ci		    ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION)
248762306a36Sopenharmony_ci			bnx2i_fastpath_notification(hba, ikcqe);
248862306a36Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN)
248962306a36Sopenharmony_ci			bnx2i_process_ofld_cmpl(hba, ikcqe);
249062306a36Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN)
249162306a36Sopenharmony_ci			bnx2i_process_update_conn_cmpl(hba, ikcqe);
249262306a36Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) {
249362306a36Sopenharmony_ci			if (ikcqe->completion_status !=
249462306a36Sopenharmony_ci			    ISCSI_KCQE_COMPLETION_STATUS_SUCCESS)
249562306a36Sopenharmony_ci				bnx2i_iscsi_license_error(hba, ikcqe->\
249662306a36Sopenharmony_ci							  completion_status);
249762306a36Sopenharmony_ci			else {
249862306a36Sopenharmony_ci				set_bit(ADAPTER_STATE_UP, &hba->adapter_state);
249962306a36Sopenharmony_ci				bnx2i_get_link_state(hba);
250062306a36Sopenharmony_ci				printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: "
250162306a36Sopenharmony_ci						 "ISCSI_INIT passed\n",
250262306a36Sopenharmony_ci						 (u8)hba->pcidev->bus->number,
250362306a36Sopenharmony_ci						 hba->pci_devno,
250462306a36Sopenharmony_ci						 (u8)hba->pci_func);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci			}
250862306a36Sopenharmony_ci		} else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN)
250962306a36Sopenharmony_ci			bnx2i_process_conn_destroy_cmpl(hba, ikcqe);
251062306a36Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR)
251162306a36Sopenharmony_ci			bnx2i_process_iscsi_error(hba, ikcqe);
251262306a36Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR)
251362306a36Sopenharmony_ci			bnx2i_process_tcp_error(hba, ikcqe);
251462306a36Sopenharmony_ci		else
251562306a36Sopenharmony_ci			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
251662306a36Sopenharmony_ci					  ikcqe->op_code);
251762306a36Sopenharmony_ci	}
251862306a36Sopenharmony_ci}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci/**
252262306a36Sopenharmony_ci * bnx2i_indicate_netevent - Generic netdev event handler
252362306a36Sopenharmony_ci * @context:	adapter structure pointer
252462306a36Sopenharmony_ci * @event:	event type
252562306a36Sopenharmony_ci * @vlan_id:	vlans id - associated vlan id with this event
252662306a36Sopenharmony_ci *
252762306a36Sopenharmony_ci * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
252862306a36Sopenharmony_ci *	NETDEV_GOING_DOWN and NETDEV_CHANGE
252962306a36Sopenharmony_ci */
253062306a36Sopenharmony_cistatic void bnx2i_indicate_netevent(void *context, unsigned long event,
253162306a36Sopenharmony_ci				    u16 vlan_id)
253262306a36Sopenharmony_ci{
253362306a36Sopenharmony_ci	struct bnx2i_hba *hba = context;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	/* Ignore all netevent coming from vlans */
253662306a36Sopenharmony_ci	if (vlan_id != 0)
253762306a36Sopenharmony_ci		return;
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	switch (event) {
254062306a36Sopenharmony_ci	case NETDEV_UP:
254162306a36Sopenharmony_ci		if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
254262306a36Sopenharmony_ci			bnx2i_send_fw_iscsi_init_msg(hba);
254362306a36Sopenharmony_ci		break;
254462306a36Sopenharmony_ci	case NETDEV_DOWN:
254562306a36Sopenharmony_ci		clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
254662306a36Sopenharmony_ci		clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
254762306a36Sopenharmony_ci		break;
254862306a36Sopenharmony_ci	case NETDEV_GOING_DOWN:
254962306a36Sopenharmony_ci		set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
255062306a36Sopenharmony_ci		iscsi_host_for_each_session(hba->shost,
255162306a36Sopenharmony_ci					    bnx2i_drop_session);
255262306a36Sopenharmony_ci		break;
255362306a36Sopenharmony_ci	case NETDEV_CHANGE:
255462306a36Sopenharmony_ci		bnx2i_get_link_state(hba);
255562306a36Sopenharmony_ci		break;
255662306a36Sopenharmony_ci	default:
255762306a36Sopenharmony_ci		;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci/**
256362306a36Sopenharmony_ci * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion
256462306a36Sopenharmony_ci * @cm_sk: 		cnic sock structure pointer
256562306a36Sopenharmony_ci *
256662306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
256762306a36Sopenharmony_ci *	indicate completion of option-2 TCP connect request.
256862306a36Sopenharmony_ci */
256962306a36Sopenharmony_cistatic void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk)
257062306a36Sopenharmony_ci{
257162306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
257462306a36Sopenharmony_ci		ep->state = EP_STATE_CONNECT_FAILED;
257562306a36Sopenharmony_ci	else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags))
257662306a36Sopenharmony_ci		ep->state = EP_STATE_CONNECT_COMPL;
257762306a36Sopenharmony_ci	else
257862306a36Sopenharmony_ci		ep->state = EP_STATE_CONNECT_FAILED;
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
258162306a36Sopenharmony_ci}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci/**
258562306a36Sopenharmony_ci * bnx2i_cm_close_cmpl - process tcp conn close completion
258662306a36Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
258762306a36Sopenharmony_ci *
258862306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
258962306a36Sopenharmony_ci *	indicate completion of option-2 graceful TCP connect shutdown
259062306a36Sopenharmony_ci */
259162306a36Sopenharmony_cistatic void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk)
259262306a36Sopenharmony_ci{
259362306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	ep->state = EP_STATE_DISCONN_COMPL;
259662306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
259762306a36Sopenharmony_ci}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci/**
260162306a36Sopenharmony_ci * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion
260262306a36Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
260362306a36Sopenharmony_ci *
260462306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
260562306a36Sopenharmony_ci *	indicate completion of option-2 abortive TCP connect termination
260662306a36Sopenharmony_ci */
260762306a36Sopenharmony_cistatic void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	ep->state = EP_STATE_DISCONN_COMPL;
261262306a36Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
261362306a36Sopenharmony_ci}
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci/**
261762306a36Sopenharmony_ci * bnx2i_cm_remote_close - process received TCP FIN
261862306a36Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
261962306a36Sopenharmony_ci *
262062306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to indicate
262162306a36Sopenharmony_ci *	async TCP events such as FIN
262262306a36Sopenharmony_ci */
262362306a36Sopenharmony_cistatic void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	ep->state = EP_STATE_TCP_FIN_RCVD;
262862306a36Sopenharmony_ci	if (ep->conn)
262962306a36Sopenharmony_ci		bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
263062306a36Sopenharmony_ci}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci/**
263362306a36Sopenharmony_ci * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup
263462306a36Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
263562306a36Sopenharmony_ci *
263662306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
263762306a36Sopenharmony_ci *	indicate async TCP events (RST) sent by the peer.
263862306a36Sopenharmony_ci */
263962306a36Sopenharmony_cistatic void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
264262306a36Sopenharmony_ci	u32 old_state = ep->state;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	ep->state = EP_STATE_TCP_RST_RCVD;
264562306a36Sopenharmony_ci	if (old_state == EP_STATE_DISCONN_START)
264662306a36Sopenharmony_ci		wake_up_interruptible(&ep->ofld_wait);
264762306a36Sopenharmony_ci	else
264862306a36Sopenharmony_ci		if (ep->conn)
264962306a36Sopenharmony_ci			bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
265062306a36Sopenharmony_ci}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_cistatic int bnx2i_send_nl_mesg(void *context, u32 msg_type,
265462306a36Sopenharmony_ci			      char *buf, u16 buflen)
265562306a36Sopenharmony_ci{
265662306a36Sopenharmony_ci	struct bnx2i_hba *hba = context;
265762306a36Sopenharmony_ci	int rc;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (!hba)
266062306a36Sopenharmony_ci		return -ENODEV;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
266362306a36Sopenharmony_ci				msg_type, buf, buflen);
266462306a36Sopenharmony_ci	if (rc)
266562306a36Sopenharmony_ci		printk(KERN_ALERT "bnx2i: private nl message send error\n");
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	return rc;
266862306a36Sopenharmony_ci}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci/*
267262306a36Sopenharmony_ci * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure
267362306a36Sopenharmony_ci *			carrying callback function pointers
267462306a36Sopenharmony_ci */
267562306a36Sopenharmony_cistruct cnic_ulp_ops bnx2i_cnic_cb = {
267662306a36Sopenharmony_ci	.cnic_init = bnx2i_ulp_init,
267762306a36Sopenharmony_ci	.cnic_exit = bnx2i_ulp_exit,
267862306a36Sopenharmony_ci	.cnic_start = bnx2i_start,
267962306a36Sopenharmony_ci	.cnic_stop = bnx2i_stop,
268062306a36Sopenharmony_ci	.indicate_kcqes = bnx2i_indicate_kcqe,
268162306a36Sopenharmony_ci	.indicate_netevent = bnx2i_indicate_netevent,
268262306a36Sopenharmony_ci	.cm_connect_complete = bnx2i_cm_connect_cmpl,
268362306a36Sopenharmony_ci	.cm_close_complete = bnx2i_cm_close_cmpl,
268462306a36Sopenharmony_ci	.cm_abort_complete = bnx2i_cm_abort_cmpl,
268562306a36Sopenharmony_ci	.cm_remote_close = bnx2i_cm_remote_close,
268662306a36Sopenharmony_ci	.cm_remote_abort = bnx2i_cm_remote_abort,
268762306a36Sopenharmony_ci	.iscsi_nl_send_msg = bnx2i_send_nl_mesg,
268862306a36Sopenharmony_ci	.cnic_get_stats = bnx2i_get_stats,
268962306a36Sopenharmony_ci	.owner = THIS_MODULE
269062306a36Sopenharmony_ci};
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci/**
269462306a36Sopenharmony_ci * bnx2i_map_ep_dbell_regs - map connection doorbell registers
269562306a36Sopenharmony_ci * @ep: bnx2i endpoint
269662306a36Sopenharmony_ci *
269762306a36Sopenharmony_ci * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these
269862306a36Sopenharmony_ci *	register in BAR #0. Whereas in 57710 these register are accessed by
269962306a36Sopenharmony_ci *	mapping BAR #1
270062306a36Sopenharmony_ci */
270162306a36Sopenharmony_ciint bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
270262306a36Sopenharmony_ci{
270362306a36Sopenharmony_ci	u32 cid_num;
270462306a36Sopenharmony_ci	u32 reg_off;
270562306a36Sopenharmony_ci	u32 first_l4l5;
270662306a36Sopenharmony_ci	u32 ctx_sz;
270762306a36Sopenharmony_ci	u32 config2;
270862306a36Sopenharmony_ci	resource_size_t reg_base;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	cid_num = bnx2i_get_cid_num(ep);
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
271362306a36Sopenharmony_ci		reg_base = pci_resource_start(ep->hba->pcidev,
271462306a36Sopenharmony_ci					      BNX2X_DOORBELL_PCI_BAR);
271562306a36Sopenharmony_ci		reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF);
271662306a36Sopenharmony_ci		ep->qp.ctx_base = ioremap(reg_base + reg_off, 4);
271762306a36Sopenharmony_ci		if (!ep->qp.ctx_base)
271862306a36Sopenharmony_ci			return -ENOMEM;
271962306a36Sopenharmony_ci		goto arm_cq;
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci
272262306a36Sopenharmony_ci	if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
272362306a36Sopenharmony_ci	    (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
272462306a36Sopenharmony_ci		config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
272562306a36Sopenharmony_ci		first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5;
272662306a36Sopenharmony_ci		ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
272762306a36Sopenharmony_ci		if (ctx_sz)
272862306a36Sopenharmony_ci			reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
272962306a36Sopenharmony_ci				  + BNX2I_570X_PAGE_SIZE_DEFAULT *
273062306a36Sopenharmony_ci				  (((cid_num - first_l4l5) / ctx_sz) + 256);
273162306a36Sopenharmony_ci		else
273262306a36Sopenharmony_ci			reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
273362306a36Sopenharmony_ci	} else
273462306a36Sopenharmony_ci		/* 5709 device in normal node and 5706/5708 devices */
273562306a36Sopenharmony_ci		reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	ep->qp.ctx_base = ioremap(ep->hba->reg_base + reg_off,
273862306a36Sopenharmony_ci					  MB_KERNEL_CTX_SIZE);
273962306a36Sopenharmony_ci	if (!ep->qp.ctx_base)
274062306a36Sopenharmony_ci		return -ENOMEM;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ciarm_cq:
274362306a36Sopenharmony_ci	bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE);
274462306a36Sopenharmony_ci	return 0;
274562306a36Sopenharmony_ci}
2746