18c2ecf20Sopenharmony_ci/* bnx2i_hwi.c: QLogic NetXtreme II iSCSI driver.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright (c) 2006 - 2013 Broadcom Corporation
48c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
58c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008 Mike Christie
68c2ecf20Sopenharmony_ci * Copyright (c) 2014, QLogic Corporation
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
98c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
108c2ecf20Sopenharmony_ci * the Free Software Foundation.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
138c2ecf20Sopenharmony_ci * Previously Maintained by: Eddie Wai (eddie.wai@broadcom.com)
148c2ecf20Sopenharmony_ci * Maintained by: QLogic-Storage-Upstream@qlogic.com
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/gfp.h>
188c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
198c2ecf20Sopenharmony_ci#include <scsi/libiscsi.h>
208c2ecf20Sopenharmony_ci#include "bnx2i.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciDECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * bnx2i_get_cid_num - get cid from ep
268c2ecf20Sopenharmony_ci * @ep: 	endpoint pointer
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * Only applicable to 57710 family of devices
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_cistatic u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	u32 cid;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
358c2ecf20Sopenharmony_ci		cid = ep->ep_cid;
368c2ecf20Sopenharmony_ci	else
378c2ecf20Sopenharmony_ci		cid = GET_CID_NUM(ep->ep_cid);
388c2ecf20Sopenharmony_ci	return cid;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/**
438c2ecf20Sopenharmony_ci * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type
448c2ecf20Sopenharmony_ci * @hba: 		Adapter for which adjustments is to be made
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * Only applicable to 57710 family of devices
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	u32 num_elements_per_pg;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) ||
538c2ecf20Sopenharmony_ci	    test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) ||
548c2ecf20Sopenharmony_ci	    test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
558c2ecf20Sopenharmony_ci		if (!is_power_of_2(hba->max_sqes))
568c2ecf20Sopenharmony_ci			hba->max_sqes = rounddown_pow_of_two(hba->max_sqes);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		if (!is_power_of_2(hba->max_rqes))
598c2ecf20Sopenharmony_ci			hba->max_rqes = rounddown_pow_of_two(hba->max_rqes);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Adjust each queue size if the user selection does not
638c2ecf20Sopenharmony_ci	 * yield integral num of page buffers
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci	/* adjust SQ */
668c2ecf20Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
678c2ecf20Sopenharmony_ci	if (hba->max_sqes < num_elements_per_pg)
688c2ecf20Sopenharmony_ci		hba->max_sqes = num_elements_per_pg;
698c2ecf20Sopenharmony_ci	else if (hba->max_sqes % num_elements_per_pg)
708c2ecf20Sopenharmony_ci		hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) &
718c2ecf20Sopenharmony_ci				 ~(num_elements_per_pg - 1);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* adjust CQ */
748c2ecf20Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
758c2ecf20Sopenharmony_ci	if (hba->max_cqes < num_elements_per_pg)
768c2ecf20Sopenharmony_ci		hba->max_cqes = num_elements_per_pg;
778c2ecf20Sopenharmony_ci	else if (hba->max_cqes % num_elements_per_pg)
788c2ecf20Sopenharmony_ci		hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) &
798c2ecf20Sopenharmony_ci				 ~(num_elements_per_pg - 1);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* adjust RQ */
828c2ecf20Sopenharmony_ci	num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
838c2ecf20Sopenharmony_ci	if (hba->max_rqes < num_elements_per_pg)
848c2ecf20Sopenharmony_ci		hba->max_rqes = num_elements_per_pg;
858c2ecf20Sopenharmony_ci	else if (hba->max_rqes % num_elements_per_pg)
868c2ecf20Sopenharmony_ci		hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) &
878c2ecf20Sopenharmony_ci				 ~(num_elements_per_pg - 1);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/**
928c2ecf20Sopenharmony_ci * bnx2i_get_link_state - get network interface link state
938c2ecf20Sopenharmony_ci * @hba:	adapter instance pointer
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci * updates adapter structure flag based on netdev state
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_cistatic void bnx2i_get_link_state(struct bnx2i_hba *hba)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
1008c2ecf20Sopenharmony_ci		set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
1018c2ecf20Sopenharmony_ci	else
1028c2ecf20Sopenharmony_ci		clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/**
1078c2ecf20Sopenharmony_ci * bnx2i_iscsi_license_error - displays iscsi license related error message
1088c2ecf20Sopenharmony_ci * @hba:		adapter instance pointer
1098c2ecf20Sopenharmony_ci * @error_code:		error classification
1108c2ecf20Sopenharmony_ci *
1118c2ecf20Sopenharmony_ci * Puts out an error log when driver is unable to offload iscsi connection
1128c2ecf20Sopenharmony_ci *	due to license restrictions
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cistatic void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED)
1178c2ecf20Sopenharmony_ci		/* iSCSI offload not supported on this device */
1188c2ecf20Sopenharmony_ci		printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n",
1198c2ecf20Sopenharmony_ci				hba->netdev->name);
1208c2ecf20Sopenharmony_ci	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED)
1218c2ecf20Sopenharmony_ci		/* iSCSI offload not supported on this LOM device */
1228c2ecf20Sopenharmony_ci		printk(KERN_ERR "bnx2i: LOM is not enable to "
1238c2ecf20Sopenharmony_ci				"offload iSCSI connections, dev=%s\n",
1248c2ecf20Sopenharmony_ci				hba->netdev->name);
1258c2ecf20Sopenharmony_ci	set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/**
1308c2ecf20Sopenharmony_ci * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification
1318c2ecf20Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
1328c2ecf20Sopenharmony_ci * @action:	action, ARM or DISARM. For now only ARM_CQE is used
1338c2ecf20Sopenharmony_ci *
1348c2ecf20Sopenharmony_ci * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt
1358c2ecf20Sopenharmony_ci *	the driver. EQ event is generated CQ index is hit or at least 1 CQ is
1368c2ecf20Sopenharmony_ci *	outstanding and on chip timer expires
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ciint bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct bnx2i_5771x_cq_db *cq_db;
1418c2ecf20Sopenharmony_ci	u16 cq_index;
1428c2ecf20Sopenharmony_ci	u16 next_index = 0;
1438c2ecf20Sopenharmony_ci	u32 num_active_cmds;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* Coalesce CQ entries only on 10G devices */
1468c2ecf20Sopenharmony_ci	if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
1478c2ecf20Sopenharmony_ci		return 0;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* Do not update CQ DB multiple times before firmware writes
1508c2ecf20Sopenharmony_ci	 * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious
1518c2ecf20Sopenharmony_ci	 * interrupts and other unwanted results
1528c2ecf20Sopenharmony_ci	 */
1538c2ecf20Sopenharmony_ci	cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (action != CNIC_ARM_CQE_FP)
1568c2ecf20Sopenharmony_ci		if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
1578c2ecf20Sopenharmony_ci			return 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) {
1608c2ecf20Sopenharmony_ci		num_active_cmds = atomic_read(&ep->num_active_cmds);
1618c2ecf20Sopenharmony_ci		if (num_active_cmds <= event_coal_min)
1628c2ecf20Sopenharmony_ci			next_index = 1;
1638c2ecf20Sopenharmony_ci		else {
1648c2ecf20Sopenharmony_ci			next_index = num_active_cmds >> ep->ec_shift;
1658c2ecf20Sopenharmony_ci			if (next_index > num_active_cmds - event_coal_min)
1668c2ecf20Sopenharmony_ci				next_index = num_active_cmds - event_coal_min;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci		if (!next_index)
1698c2ecf20Sopenharmony_ci			next_index = 1;
1708c2ecf20Sopenharmony_ci		cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
1718c2ecf20Sopenharmony_ci		if (cq_index > ep->qp.cqe_size * 2)
1728c2ecf20Sopenharmony_ci			cq_index -= ep->qp.cqe_size * 2;
1738c2ecf20Sopenharmony_ci		if (!cq_index)
1748c2ecf20Sopenharmony_ci			cq_index = 1;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		cq_db->sqn[0] = cq_index;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	return next_index;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/**
1838c2ecf20Sopenharmony_ci * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer
1848c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection on which RQ event occurred
1858c2ecf20Sopenharmony_ci * @ptr:		driver buffer to which RQ buffer contents is to
1868c2ecf20Sopenharmony_ci *			be copied
1878c2ecf20Sopenharmony_ci * @len:		length of valid data inside RQ buf
1888c2ecf20Sopenharmony_ci *
1898c2ecf20Sopenharmony_ci * Copies RQ buffer contents from shared (DMA'able) memory region to
1908c2ecf20Sopenharmony_ci *	driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and
1918c2ecf20Sopenharmony_ci *	scsi sense info
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_civoid bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	if (!bnx2i_conn->ep->qp.rqe_left)
1968c2ecf20Sopenharmony_ci		return;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	bnx2i_conn->ep->qp.rqe_left--;
1998c2ecf20Sopenharmony_ci	memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len);
2008c2ecf20Sopenharmony_ci	if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) {
2018c2ecf20Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe;
2028c2ecf20Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_idx = 0;
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_qe++;
2058c2ecf20Sopenharmony_ci		bnx2i_conn->ep->qp.rq_cons_idx++;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct bnx2i_5771x_dbell dbell;
2138c2ecf20Sopenharmony_ci	u32 msg;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	memset(&dbell, 0, sizeof(dbell));
2168c2ecf20Sopenharmony_ci	dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE <<
2178c2ecf20Sopenharmony_ci			      B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT);
2188c2ecf20Sopenharmony_ci	msg = *((u32 *)&dbell);
2198c2ecf20Sopenharmony_ci	/* TODO : get doorbell register mapping */
2208c2ecf20Sopenharmony_ci	writel(cpu_to_le32(msg), conn->ep->qp.ctx_base);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/**
2258c2ecf20Sopenharmony_ci * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell
2268c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection on which event to post
2278c2ecf20Sopenharmony_ci * @count:	number of RQ buffer being posted to chip
2288c2ecf20Sopenharmony_ci *
2298c2ecf20Sopenharmony_ci * No need to ring hardware doorbell for 57710 family of devices
2308c2ecf20Sopenharmony_ci */
2318c2ecf20Sopenharmony_civoid bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct bnx2i_5771x_sq_rq_db *rq_db;
2348c2ecf20Sopenharmony_ci	u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000);
2358c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	ep->qp.rqe_left += count;
2388c2ecf20Sopenharmony_ci	ep->qp.rq_prod_idx &= 0x7FFF;
2398c2ecf20Sopenharmony_ci	ep->qp.rq_prod_idx += count;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) {
2428c2ecf20Sopenharmony_ci		ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes;
2438c2ecf20Sopenharmony_ci		if (!hi_bit)
2448c2ecf20Sopenharmony_ci			ep->qp.rq_prod_idx |= 0x8000;
2458c2ecf20Sopenharmony_ci	} else
2468c2ecf20Sopenharmony_ci		ep->qp.rq_prod_idx |= hi_bit;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
2498c2ecf20Sopenharmony_ci		rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt;
2508c2ecf20Sopenharmony_ci		rq_db->prod_idx = ep->qp.rq_prod_idx;
2518c2ecf20Sopenharmony_ci		/* no need to ring hardware doorbell for 57710 */
2528c2ecf20Sopenharmony_ci	} else {
2538c2ecf20Sopenharmony_ci		writew(ep->qp.rq_prod_idx,
2548c2ecf20Sopenharmony_ci		       ep->qp.ctx_base + CNIC_RECV_DOORBELL);
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/**
2608c2ecf20Sopenharmony_ci * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine
2618c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection to which new SQ entries belong
2628c2ecf20Sopenharmony_ci * @count: 		number of SQ WQEs to post
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family
2658c2ecf20Sopenharmony_ci *	of devices. For 5706/5708/5709 new SQ WQE count is written into the
2668c2ecf20Sopenharmony_ci *	doorbell register
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistatic void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct bnx2i_5771x_sq_rq_db *sq_db;
2718c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	atomic_inc(&ep->num_active_cmds);
2748c2ecf20Sopenharmony_ci	wmb();	/* flush SQ WQE memory before the doorbell is rung */
2758c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
2768c2ecf20Sopenharmony_ci		sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
2778c2ecf20Sopenharmony_ci		sq_db->prod_idx = ep->qp.sq_prod_idx;
2788c2ecf20Sopenharmony_ci		bnx2i_ring_577xx_doorbell(bnx2i_conn);
2798c2ecf20Sopenharmony_ci	} else
2808c2ecf20Sopenharmony_ci		writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/**
2858c2ecf20Sopenharmony_ci * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters
2868c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection to which new SQ entries belong
2878c2ecf20Sopenharmony_ci * @count:	number of SQ WQEs to post
2888c2ecf20Sopenharmony_ci *
2898c2ecf20Sopenharmony_ci * this routine will update SQ driver parameters and ring the doorbell
2908c2ecf20Sopenharmony_ci */
2918c2ecf20Sopenharmony_cistatic void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn,
2928c2ecf20Sopenharmony_ci					      int count)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	int tmp_cnt;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (count == 1) {
2978c2ecf20Sopenharmony_ci		if (bnx2i_conn->ep->qp.sq_prod_qe ==
2988c2ecf20Sopenharmony_ci		    bnx2i_conn->ep->qp.sq_last_qe)
2998c2ecf20Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe =
3008c2ecf20Sopenharmony_ci						bnx2i_conn->ep->qp.sq_first_qe;
3018c2ecf20Sopenharmony_ci		else
3028c2ecf20Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe++;
3038c2ecf20Sopenharmony_ci	} else {
3048c2ecf20Sopenharmony_ci		if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <=
3058c2ecf20Sopenharmony_ci		    bnx2i_conn->ep->qp.sq_last_qe)
3068c2ecf20Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe += count;
3078c2ecf20Sopenharmony_ci		else {
3088c2ecf20Sopenharmony_ci			tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe -
3098c2ecf20Sopenharmony_ci				bnx2i_conn->ep->qp.sq_prod_qe;
3108c2ecf20Sopenharmony_ci			bnx2i_conn->ep->qp.sq_prod_qe =
3118c2ecf20Sopenharmony_ci				&bnx2i_conn->ep->qp.sq_first_qe[count -
3128c2ecf20Sopenharmony_ci								(tmp_cnt + 1)];
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	bnx2i_conn->ep->qp.sq_prod_idx += count;
3168c2ecf20Sopenharmony_ci	/* Ring the doorbell */
3178c2ecf20Sopenharmony_ci	bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/**
3228c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware
3238c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
3248c2ecf20Sopenharmony_ci * @task: transport layer's command structure pointer which is requesting
3258c2ecf20Sopenharmony_ci *	  a WQE to sent to chip for further processing
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * prepare and post an iSCSI Login request WQE to CNIC firmware
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
3308c2ecf20Sopenharmony_ci			   struct iscsi_task *task)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct bnx2i_login_request *login_wqe;
3338c2ecf20Sopenharmony_ci	struct iscsi_login_req *login_hdr;
3348c2ecf20Sopenharmony_ci	u32 dword;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	login_hdr = (struct iscsi_login_req *)task->hdr;
3378c2ecf20Sopenharmony_ci	login_wqe = (struct bnx2i_login_request *)
3388c2ecf20Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	login_wqe->op_code = login_hdr->opcode;
3418c2ecf20Sopenharmony_ci	login_wqe->op_attr = login_hdr->flags;
3428c2ecf20Sopenharmony_ci	login_wqe->version_max = login_hdr->max_version;
3438c2ecf20Sopenharmony_ci	login_wqe->version_min = login_hdr->min_version;
3448c2ecf20Sopenharmony_ci	login_wqe->data_length = ntoh24(login_hdr->dlength);
3458c2ecf20Sopenharmony_ci	login_wqe->isid_lo = *((u32 *) login_hdr->isid);
3468c2ecf20Sopenharmony_ci	login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2);
3478c2ecf20Sopenharmony_ci	login_wqe->tsih = login_hdr->tsih;
3488c2ecf20Sopenharmony_ci	login_wqe->itt = task->itt |
3498c2ecf20Sopenharmony_ci		(ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT);
3508c2ecf20Sopenharmony_ci	login_wqe->cid = login_hdr->cid;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
3538c2ecf20Sopenharmony_ci	login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
3548c2ecf20Sopenharmony_ci	login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
3578c2ecf20Sopenharmony_ci	login_wqe->resp_bd_list_addr_hi =
3588c2ecf20Sopenharmony_ci		(u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) |
3618c2ecf20Sopenharmony_ci		 (bnx2i_conn->gen_pdu.resp_buf_size <<
3628c2ecf20Sopenharmony_ci		  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
3638c2ecf20Sopenharmony_ci	login_wqe->resp_buffer = dword;
3648c2ecf20Sopenharmony_ci	login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
3658c2ecf20Sopenharmony_ci	login_wqe->bd_list_addr_hi =
3668c2ecf20Sopenharmony_ci		(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
3678c2ecf20Sopenharmony_ci	login_wqe->num_bds = 1;
3688c2ecf20Sopenharmony_ci	login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
3718c2ecf20Sopenharmony_ci	return 0;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/**
3758c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware
3768c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
3778c2ecf20Sopenharmony_ci * @mtask:	driver command structure which is requesting
3788c2ecf20Sopenharmony_ci *		a WQE to sent to chip for further processing
3798c2ecf20Sopenharmony_ci *
3808c2ecf20Sopenharmony_ci * prepare and post an iSCSI Login request WQE to CNIC firmware
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
3838c2ecf20Sopenharmony_ci			 struct iscsi_task *mtask)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
3868c2ecf20Sopenharmony_ci	struct iscsi_tm *tmfabort_hdr;
3878c2ecf20Sopenharmony_ci	struct scsi_cmnd *ref_sc;
3888c2ecf20Sopenharmony_ci	struct iscsi_task *ctask;
3898c2ecf20Sopenharmony_ci	struct bnx2i_tmf_request *tmfabort_wqe;
3908c2ecf20Sopenharmony_ci	u32 dword;
3918c2ecf20Sopenharmony_ci	u32 scsi_lun[2];
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
3948c2ecf20Sopenharmony_ci	tmfabort_wqe = (struct bnx2i_tmf_request *)
3958c2ecf20Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	tmfabort_wqe->op_code = tmfabort_hdr->opcode;
3988c2ecf20Sopenharmony_ci	tmfabort_wqe->op_attr = tmfabort_hdr->flags;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
4018c2ecf20Sopenharmony_ci	tmfabort_wqe->reserved2 = 0;
4028c2ecf20Sopenharmony_ci	tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
4058c2ecf20Sopenharmony_ci	case ISCSI_TM_FUNC_ABORT_TASK:
4068c2ecf20Sopenharmony_ci	case ISCSI_TM_FUNC_TASK_REASSIGN:
4078c2ecf20Sopenharmony_ci		ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
4088c2ecf20Sopenharmony_ci		if (!ctask || !ctask->sc)
4098c2ecf20Sopenharmony_ci			/*
4108c2ecf20Sopenharmony_ci			 * the iscsi layer must have completed the cmd while
4118c2ecf20Sopenharmony_ci			 * was starting up.
4128c2ecf20Sopenharmony_ci			 *
4138c2ecf20Sopenharmony_ci			 * Note: In the case of a SCSI cmd timeout, the task's
4148c2ecf20Sopenharmony_ci			 *       sc is still active; hence ctask->sc != 0
4158c2ecf20Sopenharmony_ci			 *       In this case, the task must be aborted
4168c2ecf20Sopenharmony_ci			 */
4178c2ecf20Sopenharmony_ci			return 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		ref_sc = ctask->sc;
4208c2ecf20Sopenharmony_ci		if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
4218c2ecf20Sopenharmony_ci			dword = (ISCSI_TASK_TYPE_WRITE <<
4228c2ecf20Sopenharmony_ci				 ISCSI_CMD_REQUEST_TYPE_SHIFT);
4238c2ecf20Sopenharmony_ci		else
4248c2ecf20Sopenharmony_ci			dword = (ISCSI_TASK_TYPE_READ <<
4258c2ecf20Sopenharmony_ci				 ISCSI_CMD_REQUEST_TYPE_SHIFT);
4268c2ecf20Sopenharmony_ci		tmfabort_wqe->ref_itt = (dword |
4278c2ecf20Sopenharmony_ci					(tmfabort_hdr->rtt & ISCSI_ITT_MASK));
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci	default:
4308c2ecf20Sopenharmony_ci		tmfabort_wqe->ref_itt = RESERVED_ITT;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci	memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun));
4338c2ecf20Sopenharmony_ci	tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
4348c2ecf20Sopenharmony_ci	tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
4398c2ecf20Sopenharmony_ci	tmfabort_wqe->bd_list_addr_hi = (u32)
4408c2ecf20Sopenharmony_ci				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
4418c2ecf20Sopenharmony_ci	tmfabort_wqe->num_bds = 1;
4428c2ecf20Sopenharmony_ci	tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
4458c2ecf20Sopenharmony_ci	return 0;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/**
4498c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware
4508c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
4518c2ecf20Sopenharmony_ci * @mtask:	driver command structure which is requesting
4528c2ecf20Sopenharmony_ci *		a WQE to sent to chip for further processing
4538c2ecf20Sopenharmony_ci *
4548c2ecf20Sopenharmony_ci * prepare and post an iSCSI Text request WQE to CNIC firmware
4558c2ecf20Sopenharmony_ci */
4568c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn,
4578c2ecf20Sopenharmony_ci			  struct iscsi_task *mtask)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	struct bnx2i_text_request *text_wqe;
4608c2ecf20Sopenharmony_ci	struct iscsi_text *text_hdr;
4618c2ecf20Sopenharmony_ci	u32 dword;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	text_hdr = (struct iscsi_text *)mtask->hdr;
4648c2ecf20Sopenharmony_ci	text_wqe = (struct bnx2i_text_request *) bnx2i_conn->ep->qp.sq_prod_qe;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	memset(text_wqe, 0, sizeof(struct bnx2i_text_request));
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	text_wqe->op_code = text_hdr->opcode;
4698c2ecf20Sopenharmony_ci	text_wqe->op_attr = text_hdr->flags;
4708c2ecf20Sopenharmony_ci	text_wqe->data_length = ntoh24(text_hdr->dlength);
4718c2ecf20Sopenharmony_ci	text_wqe->itt = mtask->itt |
4728c2ecf20Sopenharmony_ci		(ISCSI_TASK_TYPE_MPATH << ISCSI_TEXT_REQUEST_TYPE_SHIFT);
4738c2ecf20Sopenharmony_ci	text_wqe->ttt = be32_to_cpu(text_hdr->ttt);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	text_wqe->cmd_sn = be32_to_cpu(text_hdr->cmdsn);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	text_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
4788c2ecf20Sopenharmony_ci	text_wqe->resp_bd_list_addr_hi =
4798c2ecf20Sopenharmony_ci			(u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	dword = ((1 << ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT) |
4828c2ecf20Sopenharmony_ci		 (bnx2i_conn->gen_pdu.resp_buf_size <<
4838c2ecf20Sopenharmony_ci		  ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
4848c2ecf20Sopenharmony_ci	text_wqe->resp_buffer = dword;
4858c2ecf20Sopenharmony_ci	text_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
4868c2ecf20Sopenharmony_ci	text_wqe->bd_list_addr_hi =
4878c2ecf20Sopenharmony_ci			(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
4888c2ecf20Sopenharmony_ci	text_wqe->num_bds = 1;
4898c2ecf20Sopenharmony_ci	text_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci/**
4978c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
4988c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
4998c2ecf20Sopenharmony_ci * @cmd:	driver command structure which is requesting
5008c2ecf20Sopenharmony_ci *		a WQE to sent to chip for further processing
5018c2ecf20Sopenharmony_ci *
5028c2ecf20Sopenharmony_ci * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware
5038c2ecf20Sopenharmony_ci */
5048c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
5058c2ecf20Sopenharmony_ci			     struct bnx2i_cmd *cmd)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct bnx2i_cmd_request *scsi_cmd_wqe;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	scsi_cmd_wqe = (struct bnx2i_cmd_request *)
5108c2ecf20Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
5118c2ecf20Sopenharmony_ci	memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request));
5128c2ecf20Sopenharmony_ci	scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/**
5198c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware
5208c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection
5218c2ecf20Sopenharmony_ci * @task:		transport layer's command structure pointer which is
5228c2ecf20Sopenharmony_ci *                      requesting a WQE to sent to chip for further processing
5238c2ecf20Sopenharmony_ci * @datap:		payload buffer pointer
5248c2ecf20Sopenharmony_ci * @data_len:		payload data length
5258c2ecf20Sopenharmony_ci * @unsol:		indicated whether nopout pdu is unsolicited pdu or
5268c2ecf20Sopenharmony_ci *			in response to target's NOPIN w/ TTT != FFFFFFFF
5278c2ecf20Sopenharmony_ci *
5288c2ecf20Sopenharmony_ci * prepare and post a nopout request WQE to CNIC firmware
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
5318c2ecf20Sopenharmony_ci			    struct iscsi_task *task,
5328c2ecf20Sopenharmony_ci			    char *datap, int data_len, int unsol)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
5358c2ecf20Sopenharmony_ci	struct bnx2i_nop_out_request *nopout_wqe;
5368c2ecf20Sopenharmony_ci	struct iscsi_nopout *nopout_hdr;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	nopout_hdr = (struct iscsi_nopout *)task->hdr;
5398c2ecf20Sopenharmony_ci	nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	memset(nopout_wqe, 0x00, sizeof(struct bnx2i_nop_out_request));
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	nopout_wqe->op_code = nopout_hdr->opcode;
5448c2ecf20Sopenharmony_ci	nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
5458c2ecf20Sopenharmony_ci	memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* 57710 requires LUN field to be swapped */
5488c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
5498c2ecf20Sopenharmony_ci		swap(nopout_wqe->lun[0], nopout_wqe->lun[1]);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	nopout_wqe->itt = ((u16)task->itt |
5528c2ecf20Sopenharmony_ci			   (ISCSI_TASK_TYPE_MPATH <<
5538c2ecf20Sopenharmony_ci			    ISCSI_TMF_REQUEST_TYPE_SHIFT));
5548c2ecf20Sopenharmony_ci	nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt);
5558c2ecf20Sopenharmony_ci	nopout_wqe->flags = 0;
5568c2ecf20Sopenharmony_ci	if (!unsol)
5578c2ecf20Sopenharmony_ci		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
5588c2ecf20Sopenharmony_ci	else if (nopout_hdr->itt == RESERVED_ITT)
5598c2ecf20Sopenharmony_ci		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
5628c2ecf20Sopenharmony_ci	nopout_wqe->data_length = data_len;
5638c2ecf20Sopenharmony_ci	if (data_len) {
5648c2ecf20Sopenharmony_ci		/* handle payload data, not required in first release */
5658c2ecf20Sopenharmony_ci		printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n");
5668c2ecf20Sopenharmony_ci	} else {
5678c2ecf20Sopenharmony_ci		nopout_wqe->bd_list_addr_lo = (u32)
5688c2ecf20Sopenharmony_ci					bnx2i_conn->hba->mp_bd_dma;
5698c2ecf20Sopenharmony_ci		nopout_wqe->bd_list_addr_hi =
5708c2ecf20Sopenharmony_ci			(u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
5718c2ecf20Sopenharmony_ci		nopout_wqe->num_bds = 1;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
5768c2ecf20Sopenharmony_ci	return 0;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci/**
5818c2ecf20Sopenharmony_ci * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware
5828c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
5838c2ecf20Sopenharmony_ci * @task:	transport layer's command structure pointer which is
5848c2ecf20Sopenharmony_ci *		requesting a WQE to sent to chip for further processing
5858c2ecf20Sopenharmony_ci *
5868c2ecf20Sopenharmony_ci * prepare and post logout request WQE to CNIC firmware
5878c2ecf20Sopenharmony_ci */
5888c2ecf20Sopenharmony_ciint bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
5898c2ecf20Sopenharmony_ci			    struct iscsi_task *task)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	struct bnx2i_logout_request *logout_wqe;
5928c2ecf20Sopenharmony_ci	struct iscsi_logout *logout_hdr;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	logout_hdr = (struct iscsi_logout *)task->hdr;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	logout_wqe = (struct bnx2i_logout_request *)
5978c2ecf20Sopenharmony_ci						bnx2i_conn->ep->qp.sq_prod_qe;
5988c2ecf20Sopenharmony_ci	memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request));
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	logout_wqe->op_code = logout_hdr->opcode;
6018c2ecf20Sopenharmony_ci	logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
6028c2ecf20Sopenharmony_ci	logout_wqe->op_attr =
6038c2ecf20Sopenharmony_ci			logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE;
6048c2ecf20Sopenharmony_ci	logout_wqe->itt = ((u16)task->itt |
6058c2ecf20Sopenharmony_ci			   (ISCSI_TASK_TYPE_MPATH <<
6068c2ecf20Sopenharmony_ci			    ISCSI_LOGOUT_REQUEST_TYPE_SHIFT));
6078c2ecf20Sopenharmony_ci	logout_wqe->data_length = 0;
6088c2ecf20Sopenharmony_ci	logout_wqe->cid = 0;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
6118c2ecf20Sopenharmony_ci	logout_wqe->bd_list_addr_hi = (u32)
6128c2ecf20Sopenharmony_ci				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
6138c2ecf20Sopenharmony_ci	logout_wqe->num_bds = 1;
6148c2ecf20Sopenharmony_ci	logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
6198c2ecf20Sopenharmony_ci	return 0;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/**
6248c2ecf20Sopenharmony_ci * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware
6258c2ecf20Sopenharmony_ci * @conn:	iscsi connection which requires iscsi parameter update
6268c2ecf20Sopenharmony_ci *
6278c2ecf20Sopenharmony_ci * sends down iSCSI Conn Update request to move iSCSI conn to FFP
6288c2ecf20Sopenharmony_ci */
6298c2ecf20Sopenharmony_civoid bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
6328c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
6338c2ecf20Sopenharmony_ci	struct kwqe *kwqe_arr[2];
6348c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_update *update_wqe;
6358c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_update conn_update_kwqe;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	update_wqe = &conn_update_kwqe;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN;
6408c2ecf20Sopenharmony_ci	update_wqe->hdr.flags =
6418c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* 5771x requires conn context id to be passed as is */
6448c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type))
6458c2ecf20Sopenharmony_ci		update_wqe->context_id = bnx2i_conn->ep->ep_cid;
6468c2ecf20Sopenharmony_ci	else
6478c2ecf20Sopenharmony_ci		update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7);
6488c2ecf20Sopenharmony_ci	update_wqe->conn_flags = 0;
6498c2ecf20Sopenharmony_ci	if (conn->hdrdgst_en)
6508c2ecf20Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST;
6518c2ecf20Sopenharmony_ci	if (conn->datadgst_en)
6528c2ecf20Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST;
6538c2ecf20Sopenharmony_ci	if (conn->session->initial_r2t_en)
6548c2ecf20Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T;
6558c2ecf20Sopenharmony_ci	if (conn->session->imm_data_en)
6568c2ecf20Sopenharmony_ci		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	update_wqe->max_send_pdu_length = conn->max_xmit_dlength;
6598c2ecf20Sopenharmony_ci	update_wqe->max_recv_pdu_length = conn->max_recv_dlength;
6608c2ecf20Sopenharmony_ci	update_wqe->first_burst_length = conn->session->first_burst;
6618c2ecf20Sopenharmony_ci	update_wqe->max_burst_length = conn->session->max_burst;
6628c2ecf20Sopenharmony_ci	update_wqe->exp_stat_sn = conn->exp_statsn;
6638c2ecf20Sopenharmony_ci	update_wqe->max_outstanding_r2ts = conn->session->max_r2t;
6648c2ecf20Sopenharmony_ci	update_wqe->session_error_recovery_level = conn->session->erl;
6658c2ecf20Sopenharmony_ci	iscsi_conn_printk(KERN_ALERT, conn,
6668c2ecf20Sopenharmony_ci			  "bnx2i: conn update - MBL 0x%x FBL 0x%x"
6678c2ecf20Sopenharmony_ci			  "MRDSL_I 0x%x MRDSL_T 0x%x \n",
6688c2ecf20Sopenharmony_ci			  update_wqe->max_burst_length,
6698c2ecf20Sopenharmony_ci			  update_wqe->first_burst_length,
6708c2ecf20Sopenharmony_ci			  update_wqe->max_recv_pdu_length,
6718c2ecf20Sopenharmony_ci			  update_wqe->max_send_pdu_length);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) update_wqe;
6748c2ecf20Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
6758c2ecf20Sopenharmony_ci		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/**
6808c2ecf20Sopenharmony_ci * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware
6818c2ecf20Sopenharmony_ci * @t:	timer context used to fetch the endpoint (transport
6828c2ecf20Sopenharmony_ci *	handle) structure pointer
6838c2ecf20Sopenharmony_ci *
6848c2ecf20Sopenharmony_ci * routine to handle connection offload/destroy request timeout
6858c2ecf20Sopenharmony_ci */
6868c2ecf20Sopenharmony_civoid bnx2i_ep_ofld_timer(struct timer_list *t)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = from_timer(ep, t, ofld_timer);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (ep->state == EP_STATE_OFLD_START) {
6918c2ecf20Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n");
6928c2ecf20Sopenharmony_ci		ep->state = EP_STATE_OFLD_FAILED;
6938c2ecf20Sopenharmony_ci	} else if (ep->state == EP_STATE_DISCONN_START) {
6948c2ecf20Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n");
6958c2ecf20Sopenharmony_ci		ep->state = EP_STATE_DISCONN_TIMEDOUT;
6968c2ecf20Sopenharmony_ci	} else if (ep->state == EP_STATE_CLEANUP_START) {
6978c2ecf20Sopenharmony_ci		printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n");
6988c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_FAILED;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic int bnx2i_power_of2(u32 val)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	u32 power = 0;
7088c2ecf20Sopenharmony_ci	if (val & (val - 1))
7098c2ecf20Sopenharmony_ci		return power;
7108c2ecf20Sopenharmony_ci	val--;
7118c2ecf20Sopenharmony_ci	while (val) {
7128c2ecf20Sopenharmony_ci		val = val >> 1;
7138c2ecf20Sopenharmony_ci		power++;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci	return power;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/**
7208c2ecf20Sopenharmony_ci * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request
7218c2ecf20Sopenharmony_ci * @hba:	adapter structure pointer
7228c2ecf20Sopenharmony_ci * @cmd:	driver command structure which is requesting
7238c2ecf20Sopenharmony_ci *		a WQE to sent to chip for further processing
7248c2ecf20Sopenharmony_ci *
7258c2ecf20Sopenharmony_ci * prepares and posts CONN_OFLD_REQ1/2 KWQE
7268c2ecf20Sopenharmony_ci */
7278c2ecf20Sopenharmony_civoid bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct bnx2i_cleanup_request *cmd_cleanup;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	cmd_cleanup =
7328c2ecf20Sopenharmony_ci		(struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe;
7338c2ecf20Sopenharmony_ci	memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request));
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST;
7368c2ecf20Sopenharmony_ci	cmd_cleanup->itt = cmd->req.itt;
7378c2ecf20Sopenharmony_ci	cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	bnx2i_ring_dbell_update_sq_params(cmd->conn, 1);
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci/**
7448c2ecf20Sopenharmony_ci * bnx2i_send_conn_destroy - initiates iscsi connection teardown process
7458c2ecf20Sopenharmony_ci * @hba:	adapter structure pointer
7468c2ecf20Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
7478c2ecf20Sopenharmony_ci *
7488c2ecf20Sopenharmony_ci * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
7498c2ecf20Sopenharmony_ci * 	iscsi connection context clean-up process
7508c2ecf20Sopenharmony_ci */
7518c2ecf20Sopenharmony_ciint bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct kwqe *kwqe_arr[2];
7548c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_destroy conn_cleanup;
7558c2ecf20Sopenharmony_ci	int rc = -EINVAL;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN;
7608c2ecf20Sopenharmony_ci	conn_cleanup.hdr.flags =
7618c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
7628c2ecf20Sopenharmony_ci	/* 5771x requires conn context id to be passed as is */
7638c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
7648c2ecf20Sopenharmony_ci		conn_cleanup.context_id = ep->ep_cid;
7658c2ecf20Sopenharmony_ci	else
7668c2ecf20Sopenharmony_ci		conn_cleanup.context_id = (ep->ep_cid >> 7);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
7718c2ecf20Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
7728c2ecf20Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	return rc;
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci/**
7798c2ecf20Sopenharmony_ci * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process
7808c2ecf20Sopenharmony_ci * @hba: 		adapter structure pointer
7818c2ecf20Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
7828c2ecf20Sopenharmony_ci *
7838c2ecf20Sopenharmony_ci * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
7848c2ecf20Sopenharmony_ci */
7858c2ecf20Sopenharmony_cistatic int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
7868c2ecf20Sopenharmony_ci					 struct bnx2i_endpoint *ep)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct kwqe *kwqe_arr[2];
7898c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_offload1 ofld_req1;
7908c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_offload2 ofld_req2;
7918c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
7928c2ecf20Sopenharmony_ci	int num_kwqes = 2;
7938c2ecf20Sopenharmony_ci	u32 *ptbl;
7948c2ecf20Sopenharmony_ci	int rc = -EINVAL;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
7978c2ecf20Sopenharmony_ci	ofld_req1.hdr.flags =
7988c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	dma_addr = ep->qp.sq_pgtbl_phys;
8038c2ecf20Sopenharmony_ci	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
8048c2ecf20Sopenharmony_ci	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	dma_addr = ep->qp.cq_pgtbl_phys;
8078c2ecf20Sopenharmony_ci	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
8088c2ecf20Sopenharmony_ci	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
8118c2ecf20Sopenharmony_ci	ofld_req2.hdr.flags =
8128c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	dma_addr = ep->qp.rq_pgtbl_phys;
8158c2ecf20Sopenharmony_ci	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
8168c2ecf20Sopenharmony_ci	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	ofld_req2.sq_first_pte.hi = *ptbl++;
8218c2ecf20Sopenharmony_ci	ofld_req2.sq_first_pte.lo = *ptbl;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
8248c2ecf20Sopenharmony_ci	ofld_req2.cq_first_pte.hi = *ptbl++;
8258c2ecf20Sopenharmony_ci	ofld_req2.cq_first_pte.lo = *ptbl;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
8288c2ecf20Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
8298c2ecf20Sopenharmony_ci	ofld_req2.num_additional_wqes = 0;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
8328c2ecf20Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	return rc;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci/**
8398c2ecf20Sopenharmony_ci * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation
8408c2ecf20Sopenharmony_ci * @hba: 		adapter structure pointer
8418c2ecf20Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
8428c2ecf20Sopenharmony_ci *
8438c2ecf20Sopenharmony_ci * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
8448c2ecf20Sopenharmony_ci */
8458c2ecf20Sopenharmony_cistatic int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
8468c2ecf20Sopenharmony_ci					  struct bnx2i_endpoint *ep)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct kwqe *kwqe_arr[5];
8498c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_offload1 ofld_req1;
8508c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_offload2 ofld_req2;
8518c2ecf20Sopenharmony_ci	struct iscsi_kwqe_conn_offload3 ofld_req3[1];
8528c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
8538c2ecf20Sopenharmony_ci	int num_kwqes = 2;
8548c2ecf20Sopenharmony_ci	u32 *ptbl;
8558c2ecf20Sopenharmony_ci	int rc = -EINVAL;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
8588c2ecf20Sopenharmony_ci	ofld_req1.hdr.flags =
8598c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE;
8648c2ecf20Sopenharmony_ci	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
8658c2ecf20Sopenharmony_ci	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE;
8688c2ecf20Sopenharmony_ci	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
8698c2ecf20Sopenharmony_ci	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
8728c2ecf20Sopenharmony_ci	ofld_req2.hdr.flags =
8738c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE;
8768c2ecf20Sopenharmony_ci	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
8778c2ecf20Sopenharmony_ci	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
8808c2ecf20Sopenharmony_ci	ofld_req2.sq_first_pte.hi = *ptbl++;
8818c2ecf20Sopenharmony_ci	ofld_req2.sq_first_pte.lo = *ptbl;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
8848c2ecf20Sopenharmony_ci	ofld_req2.cq_first_pte.hi = *ptbl++;
8858c2ecf20Sopenharmony_ci	ofld_req2.cq_first_pte.lo = *ptbl;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
8888c2ecf20Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	ofld_req2.num_additional_wqes = 1;
8918c2ecf20Sopenharmony_ci	memset(ofld_req3, 0x00, sizeof(ofld_req3[0]));
8928c2ecf20Sopenharmony_ci	ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
8938c2ecf20Sopenharmony_ci	ofld_req3[0].qp_first_pte[0].hi = *ptbl++;
8948c2ecf20Sopenharmony_ci	ofld_req3[0].qp_first_pte[0].lo = *ptbl;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	kwqe_arr[2] = (struct kwqe *) ofld_req3;
8978c2ecf20Sopenharmony_ci	/* need if we decide to go with multiple KCQE's per conn */
8988c2ecf20Sopenharmony_ci	num_kwqes += 1;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
9018c2ecf20Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	return rc;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/**
9078c2ecf20Sopenharmony_ci * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process
9088c2ecf20Sopenharmony_ci *
9098c2ecf20Sopenharmony_ci * @hba: 		adapter structure pointer
9108c2ecf20Sopenharmony_ci * @ep: 		endpoint (transport identifier) structure
9118c2ecf20Sopenharmony_ci *
9128c2ecf20Sopenharmony_ci * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
9138c2ecf20Sopenharmony_ci */
9148c2ecf20Sopenharmony_ciint bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	int rc;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
9198c2ecf20Sopenharmony_ci		rc = bnx2i_5771x_send_conn_ofld_req(hba, ep);
9208c2ecf20Sopenharmony_ci	else
9218c2ecf20Sopenharmony_ci		rc = bnx2i_570x_send_conn_ofld_req(hba, ep);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	return rc;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/**
9288c2ecf20Sopenharmony_ci * setup_qp_page_tables - iscsi QP page table setup function
9298c2ecf20Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
9308c2ecf20Sopenharmony_ci *
9318c2ecf20Sopenharmony_ci * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires
9328c2ecf20Sopenharmony_ci * 	64-bit address in big endian format. Whereas 10G/sec (57710) requires
9338c2ecf20Sopenharmony_ci * 	PT in little endian format
9348c2ecf20Sopenharmony_ci */
9358c2ecf20Sopenharmony_cistatic void setup_qp_page_tables(struct bnx2i_endpoint *ep)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	int num_pages;
9388c2ecf20Sopenharmony_ci	u32 *ptbl;
9398c2ecf20Sopenharmony_ci	dma_addr_t page;
9408c2ecf20Sopenharmony_ci	int cnic_dev_10g;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
9438c2ecf20Sopenharmony_ci		cnic_dev_10g = 1;
9448c2ecf20Sopenharmony_ci	else
9458c2ecf20Sopenharmony_ci		cnic_dev_10g = 0;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* SQ page table */
9488c2ecf20Sopenharmony_ci	memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
9498c2ecf20Sopenharmony_ci	num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
9508c2ecf20Sopenharmony_ci	page = ep->qp.sq_phys;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	if (cnic_dev_10g)
9538c2ecf20Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
9548c2ecf20Sopenharmony_ci	else
9558c2ecf20Sopenharmony_ci		ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
9568c2ecf20Sopenharmony_ci	while (num_pages--) {
9578c2ecf20Sopenharmony_ci		if (cnic_dev_10g) {
9588c2ecf20Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
9598c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
9608c2ecf20Sopenharmony_ci			ptbl++;
9618c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
9628c2ecf20Sopenharmony_ci			ptbl++;
9638c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
9648c2ecf20Sopenharmony_ci		} else {
9658c2ecf20Sopenharmony_ci			/* PTE is written in big endian format for
9668c2ecf20Sopenharmony_ci			 * 5706/5708/5709 devices */
9678c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
9688c2ecf20Sopenharmony_ci			ptbl++;
9698c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
9708c2ecf20Sopenharmony_ci			ptbl++;
9718c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
9728c2ecf20Sopenharmony_ci		}
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	/* RQ page table */
9768c2ecf20Sopenharmony_ci	memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
9778c2ecf20Sopenharmony_ci	num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
9788c2ecf20Sopenharmony_ci	page = ep->qp.rq_phys;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if (cnic_dev_10g)
9818c2ecf20Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
9828c2ecf20Sopenharmony_ci	else
9838c2ecf20Sopenharmony_ci		ptbl = (u32 *) ep->qp.rq_pgtbl_virt;
9848c2ecf20Sopenharmony_ci	while (num_pages--) {
9858c2ecf20Sopenharmony_ci		if (cnic_dev_10g) {
9868c2ecf20Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
9878c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
9888c2ecf20Sopenharmony_ci			ptbl++;
9898c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
9908c2ecf20Sopenharmony_ci			ptbl++;
9918c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
9928c2ecf20Sopenharmony_ci		} else {
9938c2ecf20Sopenharmony_ci			/* PTE is written in big endian format for
9948c2ecf20Sopenharmony_ci			 * 5706/5708/5709 devices */
9958c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
9968c2ecf20Sopenharmony_ci			ptbl++;
9978c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
9988c2ecf20Sopenharmony_ci			ptbl++;
9998c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
10008c2ecf20Sopenharmony_ci		}
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* CQ page table */
10048c2ecf20Sopenharmony_ci	memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
10058c2ecf20Sopenharmony_ci	num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
10068c2ecf20Sopenharmony_ci	page = ep->qp.cq_phys;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	if (cnic_dev_10g)
10098c2ecf20Sopenharmony_ci		ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
10108c2ecf20Sopenharmony_ci	else
10118c2ecf20Sopenharmony_ci		ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
10128c2ecf20Sopenharmony_ci	while (num_pages--) {
10138c2ecf20Sopenharmony_ci		if (cnic_dev_10g) {
10148c2ecf20Sopenharmony_ci			/* PTE is written in little endian format for 57710 */
10158c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
10168c2ecf20Sopenharmony_ci			ptbl++;
10178c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
10188c2ecf20Sopenharmony_ci			ptbl++;
10198c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
10208c2ecf20Sopenharmony_ci		} else {
10218c2ecf20Sopenharmony_ci			/* PTE is written in big endian format for
10228c2ecf20Sopenharmony_ci			 * 5706/5708/5709 devices */
10238c2ecf20Sopenharmony_ci			*ptbl = (u32) ((u64) page >> 32);
10248c2ecf20Sopenharmony_ci			ptbl++;
10258c2ecf20Sopenharmony_ci			*ptbl = (u32) page;
10268c2ecf20Sopenharmony_ci			ptbl++;
10278c2ecf20Sopenharmony_ci			page += CNIC_PAGE_SIZE;
10288c2ecf20Sopenharmony_ci		}
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci/**
10348c2ecf20Sopenharmony_ci * bnx2i_alloc_qp_resc - allocates required resources for QP.
10358c2ecf20Sopenharmony_ci * @hba:	adapter structure pointer
10368c2ecf20Sopenharmony_ci * @ep:		endpoint (transport identifier) structure
10378c2ecf20Sopenharmony_ci *
10388c2ecf20Sopenharmony_ci * Allocate QP (transport layer for iSCSI connection) resources, DMA'able
10398c2ecf20Sopenharmony_ci *	memory for SQ/RQ/CQ and page tables. EP structure elements such
10408c2ecf20Sopenharmony_ci *	as producer/consumer indexes/pointers, queue sizes and page table
10418c2ecf20Sopenharmony_ci *	contents are setup
10428c2ecf20Sopenharmony_ci */
10438c2ecf20Sopenharmony_ciint bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	struct bnx2i_5771x_cq_db *cq_db;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	ep->hba = hba;
10488c2ecf20Sopenharmony_ci	ep->conn = NULL;
10498c2ecf20Sopenharmony_ci	ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* Allocate page table memory for SQ which is page aligned */
10528c2ecf20Sopenharmony_ci	ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
10538c2ecf20Sopenharmony_ci	ep->qp.sq_mem_size =
10548c2ecf20Sopenharmony_ci		(ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
10558c2ecf20Sopenharmony_ci	ep->qp.sq_pgtbl_size =
10568c2ecf20Sopenharmony_ci		(ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
10578c2ecf20Sopenharmony_ci	ep->qp.sq_pgtbl_size =
10588c2ecf20Sopenharmony_ci		(ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	ep->qp.sq_pgtbl_virt =
10618c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
10628c2ecf20Sopenharmony_ci				   &ep->qp.sq_pgtbl_phys, GFP_KERNEL);
10638c2ecf20Sopenharmony_ci	if (!ep->qp.sq_pgtbl_virt) {
10648c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n",
10658c2ecf20Sopenharmony_ci				  ep->qp.sq_pgtbl_size);
10668c2ecf20Sopenharmony_ci		goto mem_alloc_err;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	/* Allocate memory area for actual SQ element */
10708c2ecf20Sopenharmony_ci	ep->qp.sq_virt =
10718c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
10728c2ecf20Sopenharmony_ci				   &ep->qp.sq_phys, GFP_KERNEL);
10738c2ecf20Sopenharmony_ci	if (!ep->qp.sq_virt) {
10748c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n",
10758c2ecf20Sopenharmony_ci				  ep->qp.sq_mem_size);
10768c2ecf20Sopenharmony_ci		goto mem_alloc_err;
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	ep->qp.sq_first_qe = ep->qp.sq_virt;
10808c2ecf20Sopenharmony_ci	ep->qp.sq_prod_qe = ep->qp.sq_first_qe;
10818c2ecf20Sopenharmony_ci	ep->qp.sq_cons_qe = ep->qp.sq_first_qe;
10828c2ecf20Sopenharmony_ci	ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1];
10838c2ecf20Sopenharmony_ci	ep->qp.sq_prod_idx = 0;
10848c2ecf20Sopenharmony_ci	ep->qp.sq_cons_idx = 0;
10858c2ecf20Sopenharmony_ci	ep->qp.sqe_left = hba->max_sqes;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/* Allocate page table memory for CQ which is page aligned */
10888c2ecf20Sopenharmony_ci	ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
10898c2ecf20Sopenharmony_ci	ep->qp.cq_mem_size =
10908c2ecf20Sopenharmony_ci		(ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
10918c2ecf20Sopenharmony_ci	ep->qp.cq_pgtbl_size =
10928c2ecf20Sopenharmony_ci		(ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
10938c2ecf20Sopenharmony_ci	ep->qp.cq_pgtbl_size =
10948c2ecf20Sopenharmony_ci		(ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ep->qp.cq_pgtbl_virt =
10978c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
10988c2ecf20Sopenharmony_ci				   &ep->qp.cq_pgtbl_phys, GFP_KERNEL);
10998c2ecf20Sopenharmony_ci	if (!ep->qp.cq_pgtbl_virt) {
11008c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n",
11018c2ecf20Sopenharmony_ci				  ep->qp.cq_pgtbl_size);
11028c2ecf20Sopenharmony_ci		goto mem_alloc_err;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/* Allocate memory area for actual CQ element */
11068c2ecf20Sopenharmony_ci	ep->qp.cq_virt =
11078c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
11088c2ecf20Sopenharmony_ci				   &ep->qp.cq_phys, GFP_KERNEL);
11098c2ecf20Sopenharmony_ci	if (!ep->qp.cq_virt) {
11108c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n",
11118c2ecf20Sopenharmony_ci				  ep->qp.cq_mem_size);
11128c2ecf20Sopenharmony_ci		goto mem_alloc_err;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	ep->qp.cq_first_qe = ep->qp.cq_virt;
11168c2ecf20Sopenharmony_ci	ep->qp.cq_prod_qe = ep->qp.cq_first_qe;
11178c2ecf20Sopenharmony_ci	ep->qp.cq_cons_qe = ep->qp.cq_first_qe;
11188c2ecf20Sopenharmony_ci	ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1];
11198c2ecf20Sopenharmony_ci	ep->qp.cq_prod_idx = 0;
11208c2ecf20Sopenharmony_ci	ep->qp.cq_cons_idx = 0;
11218c2ecf20Sopenharmony_ci	ep->qp.cqe_left = hba->max_cqes;
11228c2ecf20Sopenharmony_ci	ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN;
11238c2ecf20Sopenharmony_ci	ep->qp.cqe_size = hba->max_cqes;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	/* Invalidate all EQ CQE index, req only for 57710 */
11268c2ecf20Sopenharmony_ci	cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
11278c2ecf20Sopenharmony_ci	memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/* Allocate page table memory for RQ which is page aligned */
11308c2ecf20Sopenharmony_ci	ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
11318c2ecf20Sopenharmony_ci	ep->qp.rq_mem_size =
11328c2ecf20Sopenharmony_ci		(ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
11338c2ecf20Sopenharmony_ci	ep->qp.rq_pgtbl_size =
11348c2ecf20Sopenharmony_ci		(ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
11358c2ecf20Sopenharmony_ci	ep->qp.rq_pgtbl_size =
11368c2ecf20Sopenharmony_ci		(ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	ep->qp.rq_pgtbl_virt =
11398c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
11408c2ecf20Sopenharmony_ci				   &ep->qp.rq_pgtbl_phys, GFP_KERNEL);
11418c2ecf20Sopenharmony_ci	if (!ep->qp.rq_pgtbl_virt) {
11428c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n",
11438c2ecf20Sopenharmony_ci				  ep->qp.rq_pgtbl_size);
11448c2ecf20Sopenharmony_ci		goto mem_alloc_err;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	/* Allocate memory area for actual RQ element */
11488c2ecf20Sopenharmony_ci	ep->qp.rq_virt =
11498c2ecf20Sopenharmony_ci		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
11508c2ecf20Sopenharmony_ci				   &ep->qp.rq_phys, GFP_KERNEL);
11518c2ecf20Sopenharmony_ci	if (!ep->qp.rq_virt) {
11528c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n",
11538c2ecf20Sopenharmony_ci				  ep->qp.rq_mem_size);
11548c2ecf20Sopenharmony_ci		goto mem_alloc_err;
11558c2ecf20Sopenharmony_ci	}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	ep->qp.rq_first_qe = ep->qp.rq_virt;
11588c2ecf20Sopenharmony_ci	ep->qp.rq_prod_qe = ep->qp.rq_first_qe;
11598c2ecf20Sopenharmony_ci	ep->qp.rq_cons_qe = ep->qp.rq_first_qe;
11608c2ecf20Sopenharmony_ci	ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1];
11618c2ecf20Sopenharmony_ci	ep->qp.rq_prod_idx = 0x8000;
11628c2ecf20Sopenharmony_ci	ep->qp.rq_cons_idx = 0;
11638c2ecf20Sopenharmony_ci	ep->qp.rqe_left = hba->max_rqes;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	setup_qp_page_tables(ep);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	return 0;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_cimem_alloc_err:
11708c2ecf20Sopenharmony_ci	bnx2i_free_qp_resc(hba, ep);
11718c2ecf20Sopenharmony_ci	return -ENOMEM;
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci/**
11778c2ecf20Sopenharmony_ci * bnx2i_free_qp_resc - free memory resources held by QP
11788c2ecf20Sopenharmony_ci * @hba:	adapter structure pointer
11798c2ecf20Sopenharmony_ci * @ep:	endpoint (transport identifier) structure
11808c2ecf20Sopenharmony_ci *
11818c2ecf20Sopenharmony_ci * Free QP resources - SQ/RQ/CQ memory and page tables.
11828c2ecf20Sopenharmony_ci */
11838c2ecf20Sopenharmony_civoid bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	if (ep->qp.ctx_base) {
11868c2ecf20Sopenharmony_ci		iounmap(ep->qp.ctx_base);
11878c2ecf20Sopenharmony_ci		ep->qp.ctx_base = NULL;
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci	/* Free SQ mem */
11908c2ecf20Sopenharmony_ci	if (ep->qp.sq_pgtbl_virt) {
11918c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
11928c2ecf20Sopenharmony_ci				  ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys);
11938c2ecf20Sopenharmony_ci		ep->qp.sq_pgtbl_virt = NULL;
11948c2ecf20Sopenharmony_ci		ep->qp.sq_pgtbl_phys = 0;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci	if (ep->qp.sq_virt) {
11978c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
11988c2ecf20Sopenharmony_ci				  ep->qp.sq_virt, ep->qp.sq_phys);
11998c2ecf20Sopenharmony_ci		ep->qp.sq_virt = NULL;
12008c2ecf20Sopenharmony_ci		ep->qp.sq_phys = 0;
12018c2ecf20Sopenharmony_ci	}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	/* Free RQ mem */
12048c2ecf20Sopenharmony_ci	if (ep->qp.rq_pgtbl_virt) {
12058c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
12068c2ecf20Sopenharmony_ci				  ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys);
12078c2ecf20Sopenharmony_ci		ep->qp.rq_pgtbl_virt = NULL;
12088c2ecf20Sopenharmony_ci		ep->qp.rq_pgtbl_phys = 0;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci	if (ep->qp.rq_virt) {
12118c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
12128c2ecf20Sopenharmony_ci				  ep->qp.rq_virt, ep->qp.rq_phys);
12138c2ecf20Sopenharmony_ci		ep->qp.rq_virt = NULL;
12148c2ecf20Sopenharmony_ci		ep->qp.rq_phys = 0;
12158c2ecf20Sopenharmony_ci	}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	/* Free CQ mem */
12188c2ecf20Sopenharmony_ci	if (ep->qp.cq_pgtbl_virt) {
12198c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
12208c2ecf20Sopenharmony_ci				  ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys);
12218c2ecf20Sopenharmony_ci		ep->qp.cq_pgtbl_virt = NULL;
12228c2ecf20Sopenharmony_ci		ep->qp.cq_pgtbl_phys = 0;
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci	if (ep->qp.cq_virt) {
12258c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
12268c2ecf20Sopenharmony_ci				  ep->qp.cq_virt, ep->qp.cq_phys);
12278c2ecf20Sopenharmony_ci		ep->qp.cq_virt = NULL;
12288c2ecf20Sopenharmony_ci		ep->qp.cq_phys = 0;
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci/**
12348c2ecf20Sopenharmony_ci * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w
12358c2ecf20Sopenharmony_ci * @hba:	adapter structure pointer
12368c2ecf20Sopenharmony_ci *
12378c2ecf20Sopenharmony_ci * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w
12388c2ecf20Sopenharmony_ci * 	This results in iSCSi support validation and on-chip context manager
12398c2ecf20Sopenharmony_ci * 	initialization.  Firmware completes this handshake with a CQE carrying
12408c2ecf20Sopenharmony_ci * 	the result of iscsi support validation. Parameter carried by
12418c2ecf20Sopenharmony_ci * 	iscsi init request determines the number of offloaded connection and
12428c2ecf20Sopenharmony_ci * 	tolerance level for iscsi protocol violation this hba/chip can support
12438c2ecf20Sopenharmony_ci */
12448c2ecf20Sopenharmony_ciint bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
12458c2ecf20Sopenharmony_ci{
12468c2ecf20Sopenharmony_ci	struct kwqe *kwqe_arr[3];
12478c2ecf20Sopenharmony_ci	struct iscsi_kwqe_init1 iscsi_init;
12488c2ecf20Sopenharmony_ci	struct iscsi_kwqe_init2 iscsi_init2;
12498c2ecf20Sopenharmony_ci	int rc = 0;
12508c2ecf20Sopenharmony_ci	u64 mask64;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1));
12538c2ecf20Sopenharmony_ci	memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2));
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	bnx2i_adjust_qp_size(hba);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	iscsi_init.flags =
12588c2ecf20Sopenharmony_ci		(CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
12598c2ecf20Sopenharmony_ci	if (en_tcp_dack)
12608c2ecf20Sopenharmony_ci		iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
12618c2ecf20Sopenharmony_ci	iscsi_init.reserved0 = 0;
12628c2ecf20Sopenharmony_ci	iscsi_init.num_cqs = 1;
12638c2ecf20Sopenharmony_ci	iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1;
12648c2ecf20Sopenharmony_ci	iscsi_init.hdr.flags =
12658c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma;
12688c2ecf20Sopenharmony_ci	iscsi_init.dummy_buffer_addr_hi =
12698c2ecf20Sopenharmony_ci		(u32) ((u64) hba->dummy_buf_dma >> 32);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	hba->num_ccell = hba->max_sqes >> 1;
12728c2ecf20Sopenharmony_ci	hba->ctx_ccell_tasks =
12738c2ecf20Sopenharmony_ci			((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
12748c2ecf20Sopenharmony_ci	iscsi_init.num_ccells_per_conn = hba->num_ccell;
12758c2ecf20Sopenharmony_ci	iscsi_init.num_tasks_per_conn = hba->max_sqes;
12768c2ecf20Sopenharmony_ci	iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
12778c2ecf20Sopenharmony_ci	iscsi_init.sq_num_wqes = hba->max_sqes;
12788c2ecf20Sopenharmony_ci	iscsi_init.cq_log_wqes_per_page =
12798c2ecf20Sopenharmony_ci		(u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
12808c2ecf20Sopenharmony_ci	iscsi_init.cq_num_wqes = hba->max_cqes;
12818c2ecf20Sopenharmony_ci	iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
12828c2ecf20Sopenharmony_ci				   (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
12838c2ecf20Sopenharmony_ci	iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
12848c2ecf20Sopenharmony_ci				   (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
12858c2ecf20Sopenharmony_ci	iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
12868c2ecf20Sopenharmony_ci	iscsi_init.rq_num_wqes = hba->max_rqes;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2;
12908c2ecf20Sopenharmony_ci	iscsi_init2.hdr.flags =
12918c2ecf20Sopenharmony_ci		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
12928c2ecf20Sopenharmony_ci	iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1;
12938c2ecf20Sopenharmony_ci	mask64 = 0x0ULL;
12948c2ecf20Sopenharmony_ci	mask64 |= (
12958c2ecf20Sopenharmony_ci		/* CISCO MDS */
12968c2ecf20Sopenharmony_ci		(1UL <<
12978c2ecf20Sopenharmony_ci		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) |
12988c2ecf20Sopenharmony_ci		/* HP MSA1510i */
12998c2ecf20Sopenharmony_ci		(1UL <<
13008c2ecf20Sopenharmony_ci		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
13018c2ecf20Sopenharmony_ci		/* EMC */
13028c2ecf20Sopenharmony_ci		(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
13038c2ecf20Sopenharmony_ci	if (error_mask1) {
13048c2ecf20Sopenharmony_ci		iscsi_init2.error_bit_map[0] = error_mask1;
13058c2ecf20Sopenharmony_ci		mask64 ^= (u32)(mask64);
13068c2ecf20Sopenharmony_ci		mask64 |= error_mask1;
13078c2ecf20Sopenharmony_ci	} else
13088c2ecf20Sopenharmony_ci		iscsi_init2.error_bit_map[0] = (u32) mask64;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	if (error_mask2) {
13118c2ecf20Sopenharmony_ci		iscsi_init2.error_bit_map[1] = error_mask2;
13128c2ecf20Sopenharmony_ci		mask64 &= 0xffffffff;
13138c2ecf20Sopenharmony_ci		mask64 |= ((u64)error_mask2 << 32);
13148c2ecf20Sopenharmony_ci	} else
13158c2ecf20Sopenharmony_ci		iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	iscsi_error_mask = mask64;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	kwqe_arr[0] = (struct kwqe *) &iscsi_init;
13208c2ecf20Sopenharmony_ci	kwqe_arr[1] = (struct kwqe *) &iscsi_init2;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if (hba->cnic && hba->cnic->submit_kwqes)
13238c2ecf20Sopenharmony_ci		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2);
13248c2ecf20Sopenharmony_ci	return rc;
13258c2ecf20Sopenharmony_ci}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci/**
13298c2ecf20Sopenharmony_ci * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
13308c2ecf20Sopenharmony_ci * @session:	iscsi session
13318c2ecf20Sopenharmony_ci * @bnx2i_conn:	bnx2i connection
13328c2ecf20Sopenharmony_ci * @cqe:	pointer to newly DMA'ed CQE entry for processing
13338c2ecf20Sopenharmony_ci *
13348c2ecf20Sopenharmony_ci * process SCSI CMD Response CQE & complete the request to SCSI-ML
13358c2ecf20Sopenharmony_ci */
13368c2ecf20Sopenharmony_ciint bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
13378c2ecf20Sopenharmony_ci				struct bnx2i_conn *bnx2i_conn,
13388c2ecf20Sopenharmony_ci				struct cqe *cqe)
13398c2ecf20Sopenharmony_ci{
13408c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
13418c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
13428c2ecf20Sopenharmony_ci	struct bnx2i_cmd_response *resp_cqe;
13438c2ecf20Sopenharmony_ci	struct bnx2i_cmd *bnx2i_cmd;
13448c2ecf20Sopenharmony_ci	struct iscsi_task *task;
13458c2ecf20Sopenharmony_ci	struct iscsi_scsi_rsp *hdr;
13468c2ecf20Sopenharmony_ci	u32 datalen = 0;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	resp_cqe = (struct bnx2i_cmd_response *)cqe;
13498c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
13508c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
13518c2ecf20Sopenharmony_ci				 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
13528c2ecf20Sopenharmony_ci	if (!task)
13538c2ecf20Sopenharmony_ci		goto fail;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	bnx2i_cmd = task->dd_data;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) {
13588c2ecf20Sopenharmony_ci		conn->datain_pdus_cnt +=
13598c2ecf20Sopenharmony_ci			resp_cqe->task_stat.read_stat.num_data_ins;
13608c2ecf20Sopenharmony_ci		conn->rxdata_octets +=
13618c2ecf20Sopenharmony_ci			bnx2i_cmd->req.total_data_transfer_length;
13628c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus,
13638c2ecf20Sopenharmony_ci			     resp_cqe->task_stat.read_stat.num_data_ins);
13648c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, rx_bytes,
13658c2ecf20Sopenharmony_ci			     bnx2i_cmd->req.total_data_transfer_length);
13668c2ecf20Sopenharmony_ci	} else {
13678c2ecf20Sopenharmony_ci		conn->dataout_pdus_cnt +=
13688c2ecf20Sopenharmony_ci			resp_cqe->task_stat.write_stat.num_data_outs;
13698c2ecf20Sopenharmony_ci		conn->r2t_pdus_cnt +=
13708c2ecf20Sopenharmony_ci			resp_cqe->task_stat.write_stat.num_r2ts;
13718c2ecf20Sopenharmony_ci		conn->txdata_octets +=
13728c2ecf20Sopenharmony_ci			bnx2i_cmd->req.total_data_transfer_length;
13738c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, tx_pdus,
13748c2ecf20Sopenharmony_ci			     resp_cqe->task_stat.write_stat.num_data_outs);
13758c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, tx_bytes,
13768c2ecf20Sopenharmony_ci			     bnx2i_cmd->req.total_data_transfer_length);
13778c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus,
13788c2ecf20Sopenharmony_ci			     resp_cqe->task_stat.write_stat.num_r2ts);
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci	bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	hdr = (struct iscsi_scsi_rsp *)task->hdr;
13838c2ecf20Sopenharmony_ci	resp_cqe = (struct bnx2i_cmd_response *)cqe;
13848c2ecf20Sopenharmony_ci	hdr->opcode = resp_cqe->op_code;
13858c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
13868c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn);
13878c2ecf20Sopenharmony_ci	hdr->response = resp_cqe->response;
13888c2ecf20Sopenharmony_ci	hdr->cmd_status = resp_cqe->status;
13898c2ecf20Sopenharmony_ci	hdr->flags = resp_cqe->response_flags;
13908c2ecf20Sopenharmony_ci	hdr->residual_count = cpu_to_be32(resp_cqe->residual_count);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN)
13938c2ecf20Sopenharmony_ci		goto done;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) {
13968c2ecf20Sopenharmony_ci		datalen = resp_cqe->data_length;
13978c2ecf20Sopenharmony_ci		if (datalen < 2)
13988c2ecf20Sopenharmony_ci			goto done;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci		if (datalen > BNX2I_RQ_WQE_SIZE) {
14018c2ecf20Sopenharmony_ci			iscsi_conn_printk(KERN_ERR, conn,
14028c2ecf20Sopenharmony_ci					  "sense data len %d > RQ sz\n",
14038c2ecf20Sopenharmony_ci					  datalen);
14048c2ecf20Sopenharmony_ci			datalen = BNX2I_RQ_WQE_SIZE;
14058c2ecf20Sopenharmony_ci		} else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) {
14068c2ecf20Sopenharmony_ci			iscsi_conn_printk(KERN_ERR, conn,
14078c2ecf20Sopenharmony_ci					  "sense data len %d > conn data\n",
14088c2ecf20Sopenharmony_ci					  datalen);
14098c2ecf20Sopenharmony_ci			datalen = ISCSI_DEF_MAX_RECV_SEG_LEN;
14108c2ecf20Sopenharmony_ci		}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci		bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen);
14138c2ecf20Sopenharmony_ci		bnx2i_put_rq_buf(bnx2i_cmd->conn, 1);
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cidone:
14178c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
14188c2ecf20Sopenharmony_ci			     conn->data, datalen);
14198c2ecf20Sopenharmony_cifail:
14208c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
14218c2ecf20Sopenharmony_ci	return 0;
14228c2ecf20Sopenharmony_ci}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci/**
14268c2ecf20Sopenharmony_ci * bnx2i_process_login_resp - this function handles iscsi login response
14278c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
14288c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
14298c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
14308c2ecf20Sopenharmony_ci *
14318c2ecf20Sopenharmony_ci * process Login Response CQE & complete it to open-iscsi user daemon
14328c2ecf20Sopenharmony_ci */
14338c2ecf20Sopenharmony_cistatic int bnx2i_process_login_resp(struct iscsi_session *session,
14348c2ecf20Sopenharmony_ci				    struct bnx2i_conn *bnx2i_conn,
14358c2ecf20Sopenharmony_ci				    struct cqe *cqe)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
14388c2ecf20Sopenharmony_ci	struct iscsi_task *task;
14398c2ecf20Sopenharmony_ci	struct bnx2i_login_response *login;
14408c2ecf20Sopenharmony_ci	struct iscsi_login_rsp *resp_hdr;
14418c2ecf20Sopenharmony_ci	int pld_len;
14428c2ecf20Sopenharmony_ci	int pad_len;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	login = (struct bnx2i_login_response *) cqe;
14458c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
14468c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
14478c2ecf20Sopenharmony_ci				 login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
14488c2ecf20Sopenharmony_ci	if (!task)
14498c2ecf20Sopenharmony_ci		goto done;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
14528c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
14538c2ecf20Sopenharmony_ci	resp_hdr->opcode = login->op_code;
14548c2ecf20Sopenharmony_ci	resp_hdr->flags = login->response_flags;
14558c2ecf20Sopenharmony_ci	resp_hdr->max_version = login->version_max;
14568c2ecf20Sopenharmony_ci	resp_hdr->active_version = login->version_active;
14578c2ecf20Sopenharmony_ci	resp_hdr->hlength = 0;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	hton24(resp_hdr->dlength, login->data_length);
14608c2ecf20Sopenharmony_ci	memcpy(resp_hdr->isid, &login->isid_lo, 6);
14618c2ecf20Sopenharmony_ci	resp_hdr->tsih = cpu_to_be16(login->tsih);
14628c2ecf20Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
14638c2ecf20Sopenharmony_ci	resp_hdr->statsn = cpu_to_be32(login->stat_sn);
14648c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn);
14658c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn);
14668c2ecf20Sopenharmony_ci	resp_hdr->status_class = login->status_class;
14678c2ecf20Sopenharmony_ci	resp_hdr->status_detail = login->status_detail;
14688c2ecf20Sopenharmony_ci	pld_len = login->data_length;
14698c2ecf20Sopenharmony_ci	bnx2i_conn->gen_pdu.resp_wr_ptr =
14708c2ecf20Sopenharmony_ci					bnx2i_conn->gen_pdu.resp_buf + pld_len;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	pad_len = 0;
14738c2ecf20Sopenharmony_ci	if (pld_len & 0x3)
14748c2ecf20Sopenharmony_ci		pad_len = 4 - (pld_len % 4);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	if (pad_len) {
14778c2ecf20Sopenharmony_ci		int i = 0;
14788c2ecf20Sopenharmony_ci		for (i = 0; i < pad_len; i++) {
14798c2ecf20Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
14808c2ecf20Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr++;
14818c2ecf20Sopenharmony_ci		}
14828c2ecf20Sopenharmony_ci	}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
14858c2ecf20Sopenharmony_ci		bnx2i_conn->gen_pdu.resp_buf,
14868c2ecf20Sopenharmony_ci		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
14878c2ecf20Sopenharmony_cidone:
14888c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
14898c2ecf20Sopenharmony_ci	return 0;
14908c2ecf20Sopenharmony_ci}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci/**
14948c2ecf20Sopenharmony_ci * bnx2i_process_text_resp - this function handles iscsi text response
14958c2ecf20Sopenharmony_ci * @session:	iscsi session pointer
14968c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection pointer
14978c2ecf20Sopenharmony_ci * @cqe:	pointer to newly DMA'ed CQE entry for processing
14988c2ecf20Sopenharmony_ci *
14998c2ecf20Sopenharmony_ci * process iSCSI Text Response CQE&  complete it to open-iscsi user daemon
15008c2ecf20Sopenharmony_ci */
15018c2ecf20Sopenharmony_cistatic int bnx2i_process_text_resp(struct iscsi_session *session,
15028c2ecf20Sopenharmony_ci				   struct bnx2i_conn *bnx2i_conn,
15038c2ecf20Sopenharmony_ci				   struct cqe *cqe)
15048c2ecf20Sopenharmony_ci{
15058c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
15068c2ecf20Sopenharmony_ci	struct iscsi_task *task;
15078c2ecf20Sopenharmony_ci	struct bnx2i_text_response *text;
15088c2ecf20Sopenharmony_ci	struct iscsi_text_rsp *resp_hdr;
15098c2ecf20Sopenharmony_ci	int pld_len;
15108c2ecf20Sopenharmony_ci	int pad_len;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	text = (struct bnx2i_text_response *) cqe;
15138c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
15148c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
15158c2ecf20Sopenharmony_ci	if (!task)
15168c2ecf20Sopenharmony_ci		goto done;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_text_rsp *)&bnx2i_conn->gen_pdu.resp_hdr;
15198c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
15208c2ecf20Sopenharmony_ci	resp_hdr->opcode = text->op_code;
15218c2ecf20Sopenharmony_ci	resp_hdr->flags = text->response_flags;
15228c2ecf20Sopenharmony_ci	resp_hdr->hlength = 0;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	hton24(resp_hdr->dlength, text->data_length);
15258c2ecf20Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
15268c2ecf20Sopenharmony_ci	resp_hdr->ttt = cpu_to_be32(text->ttt);
15278c2ecf20Sopenharmony_ci	resp_hdr->statsn = task->hdr->exp_statsn;
15288c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(text->exp_cmd_sn);
15298c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(text->max_cmd_sn);
15308c2ecf20Sopenharmony_ci	pld_len = text->data_length;
15318c2ecf20Sopenharmony_ci	bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf +
15328c2ecf20Sopenharmony_ci					  pld_len;
15338c2ecf20Sopenharmony_ci	pad_len = 0;
15348c2ecf20Sopenharmony_ci	if (pld_len & 0x3)
15358c2ecf20Sopenharmony_ci		pad_len = 4 - (pld_len % 4);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	if (pad_len) {
15388c2ecf20Sopenharmony_ci		int i = 0;
15398c2ecf20Sopenharmony_ci		for (i = 0; i < pad_len; i++) {
15408c2ecf20Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
15418c2ecf20Sopenharmony_ci			bnx2i_conn->gen_pdu.resp_wr_ptr++;
15428c2ecf20Sopenharmony_ci		}
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
15458c2ecf20Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_buf,
15468c2ecf20Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_wr_ptr -
15478c2ecf20Sopenharmony_ci			     bnx2i_conn->gen_pdu.resp_buf);
15488c2ecf20Sopenharmony_cidone:
15498c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
15508c2ecf20Sopenharmony_ci	return 0;
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci/**
15558c2ecf20Sopenharmony_ci * bnx2i_process_tmf_resp - this function handles iscsi TMF response
15568c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
15578c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
15588c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
15598c2ecf20Sopenharmony_ci *
15608c2ecf20Sopenharmony_ci * process iSCSI TMF Response CQE and wake up the driver eh thread.
15618c2ecf20Sopenharmony_ci */
15628c2ecf20Sopenharmony_cistatic int bnx2i_process_tmf_resp(struct iscsi_session *session,
15638c2ecf20Sopenharmony_ci				  struct bnx2i_conn *bnx2i_conn,
15648c2ecf20Sopenharmony_ci				  struct cqe *cqe)
15658c2ecf20Sopenharmony_ci{
15668c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
15678c2ecf20Sopenharmony_ci	struct iscsi_task *task;
15688c2ecf20Sopenharmony_ci	struct bnx2i_tmf_response *tmf_cqe;
15698c2ecf20Sopenharmony_ci	struct iscsi_tm_rsp *resp_hdr;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	tmf_cqe = (struct bnx2i_tmf_response *)cqe;
15728c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
15738c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
15748c2ecf20Sopenharmony_ci				 tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
15758c2ecf20Sopenharmony_ci	if (!task)
15768c2ecf20Sopenharmony_ci		goto done;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
15798c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
15808c2ecf20Sopenharmony_ci	resp_hdr->opcode = tmf_cqe->op_code;
15818c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn);
15828c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn);
15838c2ecf20Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
15848c2ecf20Sopenharmony_ci	resp_hdr->response = tmf_cqe->response;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
15878c2ecf20Sopenharmony_cidone:
15888c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
15898c2ecf20Sopenharmony_ci	return 0;
15908c2ecf20Sopenharmony_ci}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci/**
15938c2ecf20Sopenharmony_ci * bnx2i_process_logout_resp - this function handles iscsi logout response
15948c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
15958c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
15968c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
15978c2ecf20Sopenharmony_ci *
15988c2ecf20Sopenharmony_ci * process iSCSI Logout Response CQE & make function call to
15998c2ecf20Sopenharmony_ci * notify the user daemon.
16008c2ecf20Sopenharmony_ci */
16018c2ecf20Sopenharmony_cistatic int bnx2i_process_logout_resp(struct iscsi_session *session,
16028c2ecf20Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
16038c2ecf20Sopenharmony_ci				     struct cqe *cqe)
16048c2ecf20Sopenharmony_ci{
16058c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
16068c2ecf20Sopenharmony_ci	struct iscsi_task *task;
16078c2ecf20Sopenharmony_ci	struct bnx2i_logout_response *logout;
16088c2ecf20Sopenharmony_ci	struct iscsi_logout_rsp *resp_hdr;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	logout = (struct bnx2i_logout_response *) cqe;
16118c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
16128c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
16138c2ecf20Sopenharmony_ci				 logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
16148c2ecf20Sopenharmony_ci	if (!task)
16158c2ecf20Sopenharmony_ci		goto done;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
16188c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
16198c2ecf20Sopenharmony_ci	resp_hdr->opcode = logout->op_code;
16208c2ecf20Sopenharmony_ci	resp_hdr->flags = logout->response;
16218c2ecf20Sopenharmony_ci	resp_hdr->hlength = 0;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	resp_hdr->itt = task->hdr->itt;
16248c2ecf20Sopenharmony_ci	resp_hdr->statsn = task->hdr->exp_statsn;
16258c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn);
16268c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
16298c2ecf20Sopenharmony_ci	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
16348c2ecf20Sopenharmony_cidone:
16358c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
16368c2ecf20Sopenharmony_ci	return 0;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci/**
16408c2ecf20Sopenharmony_ci * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE
16418c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
16428c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
16438c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
16448c2ecf20Sopenharmony_ci *
16458c2ecf20Sopenharmony_ci * process iSCSI NOPIN local completion CQE, frees IIT and command structures
16468c2ecf20Sopenharmony_ci */
16478c2ecf20Sopenharmony_cistatic void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
16488c2ecf20Sopenharmony_ci					   struct bnx2i_conn *bnx2i_conn,
16498c2ecf20Sopenharmony_ci					   struct cqe *cqe)
16508c2ecf20Sopenharmony_ci{
16518c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
16528c2ecf20Sopenharmony_ci	struct bnx2i_nop_in_msg *nop_in;
16538c2ecf20Sopenharmony_ci	struct iscsi_task *task;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	nop_in = (struct bnx2i_nop_in_msg *)cqe;
16568c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
16578c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
16588c2ecf20Sopenharmony_ci				 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
16598c2ecf20Sopenharmony_ci	if (task)
16608c2ecf20Sopenharmony_ci		__iscsi_put_task(task);
16618c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci/**
16658c2ecf20Sopenharmony_ci * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd
16668c2ecf20Sopenharmony_ci * @bnx2i_conn:	iscsi connection
16678c2ecf20Sopenharmony_ci *
16688c2ecf20Sopenharmony_ci * Firmware advances RQ producer index for every unsolicited PDU even if
16698c2ecf20Sopenharmony_ci *	payload data length is '0'. This function makes corresponding
16708c2ecf20Sopenharmony_ci *	adjustments on the driver side to match this f/w behavior
16718c2ecf20Sopenharmony_ci */
16728c2ecf20Sopenharmony_cistatic void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn)
16738c2ecf20Sopenharmony_ci{
16748c2ecf20Sopenharmony_ci	char dummy_rq_data[2];
16758c2ecf20Sopenharmony_ci	bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1);
16768c2ecf20Sopenharmony_ci	bnx2i_put_rq_buf(bnx2i_conn, 1);
16778c2ecf20Sopenharmony_ci}
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci/**
16818c2ecf20Sopenharmony_ci * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE
16828c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
16838c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
16848c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
16858c2ecf20Sopenharmony_ci *
16868c2ecf20Sopenharmony_ci * process iSCSI target's proactive iSCSI NOPIN request
16878c2ecf20Sopenharmony_ci */
16888c2ecf20Sopenharmony_cistatic int bnx2i_process_nopin_mesg(struct iscsi_session *session,
16898c2ecf20Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
16908c2ecf20Sopenharmony_ci				     struct cqe *cqe)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
16938c2ecf20Sopenharmony_ci	struct iscsi_task *task;
16948c2ecf20Sopenharmony_ci	struct bnx2i_nop_in_msg *nop_in;
16958c2ecf20Sopenharmony_ci	struct iscsi_nopin *hdr;
16968c2ecf20Sopenharmony_ci	int tgt_async_nop = 0;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	nop_in = (struct bnx2i_nop_in_msg *)cqe;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
17018c2ecf20Sopenharmony_ci	hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
17028c2ecf20Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
17038c2ecf20Sopenharmony_ci	hdr->opcode = nop_in->op_code;
17048c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn);
17058c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
17068c2ecf20Sopenharmony_ci	hdr->ttt = cpu_to_be32(nop_in->ttt);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	if (nop_in->itt == (u16) RESERVED_ITT) {
17098c2ecf20Sopenharmony_ci		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
17108c2ecf20Sopenharmony_ci		hdr->itt = RESERVED_ITT;
17118c2ecf20Sopenharmony_ci		tgt_async_nop = 1;
17128c2ecf20Sopenharmony_ci		goto done;
17138c2ecf20Sopenharmony_ci	}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	/* this is a response to one of our nop-outs */
17168c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
17178c2ecf20Sopenharmony_ci			 (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX));
17188c2ecf20Sopenharmony_ci	if (task) {
17198c2ecf20Sopenharmony_ci		hdr->flags = ISCSI_FLAG_CMD_FINAL;
17208c2ecf20Sopenharmony_ci		hdr->itt = task->hdr->itt;
17218c2ecf20Sopenharmony_ci		hdr->ttt = cpu_to_be32(nop_in->ttt);
17228c2ecf20Sopenharmony_ci		memcpy(&hdr->lun, nop_in->lun, 8);
17238c2ecf20Sopenharmony_ci	}
17248c2ecf20Sopenharmony_cidone:
17258c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
17268c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	return tgt_async_nop;
17298c2ecf20Sopenharmony_ci}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci/**
17338c2ecf20Sopenharmony_ci * bnx2i_process_async_mesg - this function handles iscsi async message
17348c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
17358c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
17368c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
17378c2ecf20Sopenharmony_ci *
17388c2ecf20Sopenharmony_ci * process iSCSI ASYNC Message
17398c2ecf20Sopenharmony_ci */
17408c2ecf20Sopenharmony_cistatic void bnx2i_process_async_mesg(struct iscsi_session *session,
17418c2ecf20Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
17428c2ecf20Sopenharmony_ci				     struct cqe *cqe)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	struct bnx2i_async_msg *async_cqe;
17458c2ecf20Sopenharmony_ci	struct iscsi_async *resp_hdr;
17468c2ecf20Sopenharmony_ci	u8 async_event;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	async_cqe = (struct bnx2i_async_msg *)cqe;
17518c2ecf20Sopenharmony_ci	async_event = async_cqe->async_event;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) {
17548c2ecf20Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
17558c2ecf20Sopenharmony_ci				  "async: scsi events not supported\n");
17568c2ecf20Sopenharmony_ci		return;
17578c2ecf20Sopenharmony_ci	}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
17608c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
17618c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
17628c2ecf20Sopenharmony_ci	resp_hdr->opcode = async_cqe->op_code;
17638c2ecf20Sopenharmony_ci	resp_hdr->flags = 0x80;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	memcpy(&resp_hdr->lun, async_cqe->lun, 8);
17668c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
17678c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	resp_hdr->async_event = async_cqe->async_event;
17708c2ecf20Sopenharmony_ci	resp_hdr->async_vcode = async_cqe->async_vcode;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	resp_hdr->param1 = cpu_to_be16(async_cqe->param1);
17738c2ecf20Sopenharmony_ci	resp_hdr->param2 = cpu_to_be16(async_cqe->param2);
17748c2ecf20Sopenharmony_ci	resp_hdr->param3 = cpu_to_be16(async_cqe->param3);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
17778c2ecf20Sopenharmony_ci			     (struct iscsi_hdr *)resp_hdr, NULL, 0);
17788c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci/**
17838c2ecf20Sopenharmony_ci * bnx2i_process_reject_mesg - process iscsi reject pdu
17848c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
17858c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
17868c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
17878c2ecf20Sopenharmony_ci *
17888c2ecf20Sopenharmony_ci * process iSCSI REJECT message
17898c2ecf20Sopenharmony_ci */
17908c2ecf20Sopenharmony_cistatic void bnx2i_process_reject_mesg(struct iscsi_session *session,
17918c2ecf20Sopenharmony_ci				      struct bnx2i_conn *bnx2i_conn,
17928c2ecf20Sopenharmony_ci				      struct cqe *cqe)
17938c2ecf20Sopenharmony_ci{
17948c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
17958c2ecf20Sopenharmony_ci	struct bnx2i_reject_msg *reject;
17968c2ecf20Sopenharmony_ci	struct iscsi_reject *hdr;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	reject = (struct bnx2i_reject_msg *) cqe;
17998c2ecf20Sopenharmony_ci	if (reject->data_length) {
18008c2ecf20Sopenharmony_ci		bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length);
18018c2ecf20Sopenharmony_ci		bnx2i_put_rq_buf(bnx2i_conn, 1);
18028c2ecf20Sopenharmony_ci	} else
18038c2ecf20Sopenharmony_ci		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
18068c2ecf20Sopenharmony_ci	hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
18078c2ecf20Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
18088c2ecf20Sopenharmony_ci	hdr->opcode = reject->op_code;
18098c2ecf20Sopenharmony_ci	hdr->reason = reject->reason;
18108c2ecf20Sopenharmony_ci	hton24(hdr->dlength, reject->data_length);
18118c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn);
18128c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn);
18138c2ecf20Sopenharmony_ci	hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
18148c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
18158c2ecf20Sopenharmony_ci			     reject->data_length);
18168c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
18178c2ecf20Sopenharmony_ci}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci/**
18208c2ecf20Sopenharmony_ci * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion
18218c2ecf20Sopenharmony_ci * @session:		iscsi session pointer
18228c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection pointer
18238c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
18248c2ecf20Sopenharmony_ci *
18258c2ecf20Sopenharmony_ci * process command cleanup response CQE during conn shutdown or error recovery
18268c2ecf20Sopenharmony_ci */
18278c2ecf20Sopenharmony_cistatic void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
18288c2ecf20Sopenharmony_ci					   struct bnx2i_conn *bnx2i_conn,
18298c2ecf20Sopenharmony_ci					   struct cqe *cqe)
18308c2ecf20Sopenharmony_ci{
18318c2ecf20Sopenharmony_ci	struct bnx2i_cleanup_response *cmd_clean_rsp;
18328c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
18338c2ecf20Sopenharmony_ci	struct iscsi_task *task;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
18368c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
18378c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(conn,
18388c2ecf20Sopenharmony_ci			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
18398c2ecf20Sopenharmony_ci	if (!task)
18408c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
18418c2ecf20Sopenharmony_ci			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
18428c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
18438c2ecf20Sopenharmony_ci	complete(&bnx2i_conn->cmd_cleanup_cmpl);
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci/**
18488c2ecf20Sopenharmony_ci * bnx2i_percpu_io_thread - thread per cpu for ios
18498c2ecf20Sopenharmony_ci *
18508c2ecf20Sopenharmony_ci * @arg:	ptr to bnx2i_percpu_info structure
18518c2ecf20Sopenharmony_ci */
18528c2ecf20Sopenharmony_ciint bnx2i_percpu_io_thread(void *arg)
18538c2ecf20Sopenharmony_ci{
18548c2ecf20Sopenharmony_ci	struct bnx2i_percpu_s *p = arg;
18558c2ecf20Sopenharmony_ci	struct bnx2i_work *work, *tmp;
18568c2ecf20Sopenharmony_ci	LIST_HEAD(work_list);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	set_user_nice(current, MIN_NICE);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
18618c2ecf20Sopenharmony_ci		spin_lock_bh(&p->p_work_lock);
18628c2ecf20Sopenharmony_ci		while (!list_empty(&p->work_list)) {
18638c2ecf20Sopenharmony_ci			list_splice_init(&p->work_list, &work_list);
18648c2ecf20Sopenharmony_ci			spin_unlock_bh(&p->p_work_lock);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci			list_for_each_entry_safe(work, tmp, &work_list, list) {
18678c2ecf20Sopenharmony_ci				list_del_init(&work->list);
18688c2ecf20Sopenharmony_ci				/* work allocated in the bh, freed here */
18698c2ecf20Sopenharmony_ci				bnx2i_process_scsi_cmd_resp(work->session,
18708c2ecf20Sopenharmony_ci							    work->bnx2i_conn,
18718c2ecf20Sopenharmony_ci							    &work->cqe);
18728c2ecf20Sopenharmony_ci				atomic_dec(&work->bnx2i_conn->work_cnt);
18738c2ecf20Sopenharmony_ci				kfree(work);
18748c2ecf20Sopenharmony_ci			}
18758c2ecf20Sopenharmony_ci			spin_lock_bh(&p->p_work_lock);
18768c2ecf20Sopenharmony_ci		}
18778c2ecf20Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
18788c2ecf20Sopenharmony_ci		spin_unlock_bh(&p->p_work_lock);
18798c2ecf20Sopenharmony_ci		schedule();
18808c2ecf20Sopenharmony_ci	}
18818c2ecf20Sopenharmony_ci	__set_current_state(TASK_RUNNING);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	return 0;
18848c2ecf20Sopenharmony_ci}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci/**
18888c2ecf20Sopenharmony_ci * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread
18898c2ecf20Sopenharmony_ci * @session:		iscsi session
18908c2ecf20Sopenharmony_ci * @bnx2i_conn:		bnx2i connection
18918c2ecf20Sopenharmony_ci * @cqe:		pointer to newly DMA'ed CQE entry for processing
18928c2ecf20Sopenharmony_ci *
18938c2ecf20Sopenharmony_ci * this function is called by generic KCQ handler to queue all pending cmd
18948c2ecf20Sopenharmony_ci * completion CQEs
18958c2ecf20Sopenharmony_ci *
18968c2ecf20Sopenharmony_ci * The implementation is to queue the cmd response based on the
18978c2ecf20Sopenharmony_ci * last recorded command for the given connection.  The
18988c2ecf20Sopenharmony_ci * cpu_id gets recorded upon task_xmit.  No out-of-order completion!
18998c2ecf20Sopenharmony_ci */
19008c2ecf20Sopenharmony_cistatic int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
19018c2ecf20Sopenharmony_ci				     struct bnx2i_conn *bnx2i_conn,
19028c2ecf20Sopenharmony_ci				     struct bnx2i_nop_in_msg *cqe)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	struct bnx2i_work *bnx2i_work = NULL;
19058c2ecf20Sopenharmony_ci	struct bnx2i_percpu_s *p = NULL;
19068c2ecf20Sopenharmony_ci	struct iscsi_task *task;
19078c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc;
19088c2ecf20Sopenharmony_ci	int rc = 0;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
19118c2ecf20Sopenharmony_ci	task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
19128c2ecf20Sopenharmony_ci				 cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
19138c2ecf20Sopenharmony_ci	if (!task || !task->sc) {
19148c2ecf20Sopenharmony_ci		spin_unlock(&session->back_lock);
19158c2ecf20Sopenharmony_ci		return -EINVAL;
19168c2ecf20Sopenharmony_ci	}
19178c2ecf20Sopenharmony_ci	sc = task->sc;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	p = &per_cpu(bnx2i_percpu, blk_mq_rq_cpu(sc->request));
19228c2ecf20Sopenharmony_ci	spin_lock(&p->p_work_lock);
19238c2ecf20Sopenharmony_ci	if (unlikely(!p->iothread)) {
19248c2ecf20Sopenharmony_ci		rc = -EINVAL;
19258c2ecf20Sopenharmony_ci		goto err;
19268c2ecf20Sopenharmony_ci	}
19278c2ecf20Sopenharmony_ci	/* Alloc and copy to the cqe */
19288c2ecf20Sopenharmony_ci	bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC);
19298c2ecf20Sopenharmony_ci	if (bnx2i_work) {
19308c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&bnx2i_work->list);
19318c2ecf20Sopenharmony_ci		bnx2i_work->session = session;
19328c2ecf20Sopenharmony_ci		bnx2i_work->bnx2i_conn = bnx2i_conn;
19338c2ecf20Sopenharmony_ci		memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe));
19348c2ecf20Sopenharmony_ci		list_add_tail(&bnx2i_work->list, &p->work_list);
19358c2ecf20Sopenharmony_ci		atomic_inc(&bnx2i_conn->work_cnt);
19368c2ecf20Sopenharmony_ci		wake_up_process(p->iothread);
19378c2ecf20Sopenharmony_ci		spin_unlock(&p->p_work_lock);
19388c2ecf20Sopenharmony_ci		goto done;
19398c2ecf20Sopenharmony_ci	} else
19408c2ecf20Sopenharmony_ci		rc = -ENOMEM;
19418c2ecf20Sopenharmony_cierr:
19428c2ecf20Sopenharmony_ci	spin_unlock(&p->p_work_lock);
19438c2ecf20Sopenharmony_ci	bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe);
19448c2ecf20Sopenharmony_cidone:
19458c2ecf20Sopenharmony_ci	return rc;
19468c2ecf20Sopenharmony_ci}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci/**
19508c2ecf20Sopenharmony_ci * bnx2i_process_new_cqes - process newly DMA'ed CQE's
19518c2ecf20Sopenharmony_ci * @bnx2i_conn:		bnx2i connection
19528c2ecf20Sopenharmony_ci *
19538c2ecf20Sopenharmony_ci * this function is called by generic KCQ handler to process all pending CQE's
19548c2ecf20Sopenharmony_ci */
19558c2ecf20Sopenharmony_cistatic int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
19568c2ecf20Sopenharmony_ci{
19578c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
19588c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
19598c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = bnx2i_conn->hba;
19608c2ecf20Sopenharmony_ci	struct qp_info *qp;
19618c2ecf20Sopenharmony_ci	struct bnx2i_nop_in_msg *nopin;
19628c2ecf20Sopenharmony_ci	int tgt_async_msg;
19638c2ecf20Sopenharmony_ci	int cqe_cnt = 0;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	if (bnx2i_conn->ep == NULL)
19668c2ecf20Sopenharmony_ci		return 0;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	qp = &bnx2i_conn->ep->qp;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	if (!qp->cq_virt) {
19718c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!",
19728c2ecf20Sopenharmony_ci		       hba->netdev->name);
19738c2ecf20Sopenharmony_ci		goto out;
19748c2ecf20Sopenharmony_ci	}
19758c2ecf20Sopenharmony_ci	while (1) {
19768c2ecf20Sopenharmony_ci		nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
19778c2ecf20Sopenharmony_ci		if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
19788c2ecf20Sopenharmony_ci			break;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci		if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) {
19818c2ecf20Sopenharmony_ci			if (nopin->op_code == ISCSI_OP_NOOP_IN &&
19828c2ecf20Sopenharmony_ci			    nopin->itt == (u16) RESERVED_ITT) {
19838c2ecf20Sopenharmony_ci				printk(KERN_ALERT "bnx2i: Unsolicited "
19848c2ecf20Sopenharmony_ci				       "NOP-In detected for suspended "
19858c2ecf20Sopenharmony_ci				       "connection dev=%s!\n",
19868c2ecf20Sopenharmony_ci				       hba->netdev->name);
19878c2ecf20Sopenharmony_ci				bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
19888c2ecf20Sopenharmony_ci				goto cqe_out;
19898c2ecf20Sopenharmony_ci			}
19908c2ecf20Sopenharmony_ci			break;
19918c2ecf20Sopenharmony_ci		}
19928c2ecf20Sopenharmony_ci		tgt_async_msg = 0;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci		switch (nopin->op_code) {
19958c2ecf20Sopenharmony_ci		case ISCSI_OP_SCSI_CMD_RSP:
19968c2ecf20Sopenharmony_ci		case ISCSI_OP_SCSI_DATA_IN:
19978c2ecf20Sopenharmony_ci			/* Run the kthread engine only for data cmds
19988c2ecf20Sopenharmony_ci			   All other cmds will be completed in this bh! */
19998c2ecf20Sopenharmony_ci			bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin);
20008c2ecf20Sopenharmony_ci			goto done;
20018c2ecf20Sopenharmony_ci		case ISCSI_OP_LOGIN_RSP:
20028c2ecf20Sopenharmony_ci			bnx2i_process_login_resp(session, bnx2i_conn,
20038c2ecf20Sopenharmony_ci						 qp->cq_cons_qe);
20048c2ecf20Sopenharmony_ci			break;
20058c2ecf20Sopenharmony_ci		case ISCSI_OP_SCSI_TMFUNC_RSP:
20068c2ecf20Sopenharmony_ci			bnx2i_process_tmf_resp(session, bnx2i_conn,
20078c2ecf20Sopenharmony_ci					       qp->cq_cons_qe);
20088c2ecf20Sopenharmony_ci			break;
20098c2ecf20Sopenharmony_ci		case ISCSI_OP_TEXT_RSP:
20108c2ecf20Sopenharmony_ci			bnx2i_process_text_resp(session, bnx2i_conn,
20118c2ecf20Sopenharmony_ci						qp->cq_cons_qe);
20128c2ecf20Sopenharmony_ci			break;
20138c2ecf20Sopenharmony_ci		case ISCSI_OP_LOGOUT_RSP:
20148c2ecf20Sopenharmony_ci			bnx2i_process_logout_resp(session, bnx2i_conn,
20158c2ecf20Sopenharmony_ci						  qp->cq_cons_qe);
20168c2ecf20Sopenharmony_ci			break;
20178c2ecf20Sopenharmony_ci		case ISCSI_OP_NOOP_IN:
20188c2ecf20Sopenharmony_ci			if (bnx2i_process_nopin_mesg(session, bnx2i_conn,
20198c2ecf20Sopenharmony_ci						     qp->cq_cons_qe))
20208c2ecf20Sopenharmony_ci				tgt_async_msg = 1;
20218c2ecf20Sopenharmony_ci			break;
20228c2ecf20Sopenharmony_ci		case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION:
20238c2ecf20Sopenharmony_ci			bnx2i_process_nopin_local_cmpl(session, bnx2i_conn,
20248c2ecf20Sopenharmony_ci						       qp->cq_cons_qe);
20258c2ecf20Sopenharmony_ci			break;
20268c2ecf20Sopenharmony_ci		case ISCSI_OP_ASYNC_EVENT:
20278c2ecf20Sopenharmony_ci			bnx2i_process_async_mesg(session, bnx2i_conn,
20288c2ecf20Sopenharmony_ci						 qp->cq_cons_qe);
20298c2ecf20Sopenharmony_ci			tgt_async_msg = 1;
20308c2ecf20Sopenharmony_ci			break;
20318c2ecf20Sopenharmony_ci		case ISCSI_OP_REJECT:
20328c2ecf20Sopenharmony_ci			bnx2i_process_reject_mesg(session, bnx2i_conn,
20338c2ecf20Sopenharmony_ci						  qp->cq_cons_qe);
20348c2ecf20Sopenharmony_ci			break;
20358c2ecf20Sopenharmony_ci		case ISCSI_OPCODE_CLEANUP_RESPONSE:
20368c2ecf20Sopenharmony_ci			bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn,
20378c2ecf20Sopenharmony_ci						       qp->cq_cons_qe);
20388c2ecf20Sopenharmony_ci			break;
20398c2ecf20Sopenharmony_ci		default:
20408c2ecf20Sopenharmony_ci			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
20418c2ecf20Sopenharmony_ci					  nopin->op_code);
20428c2ecf20Sopenharmony_ci		}
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, rx_pdus, 1);
20458c2ecf20Sopenharmony_ci		ADD_STATS_64(hba, rx_bytes, nopin->data_length);
20468c2ecf20Sopenharmony_cidone:
20478c2ecf20Sopenharmony_ci		if (!tgt_async_msg) {
20488c2ecf20Sopenharmony_ci			if (!atomic_read(&bnx2i_conn->ep->num_active_cmds))
20498c2ecf20Sopenharmony_ci				printk(KERN_ALERT "bnx2i (%s): no active cmd! "
20508c2ecf20Sopenharmony_ci				       "op 0x%x\n",
20518c2ecf20Sopenharmony_ci				       hba->netdev->name,
20528c2ecf20Sopenharmony_ci				       nopin->op_code);
20538c2ecf20Sopenharmony_ci			else
20548c2ecf20Sopenharmony_ci				atomic_dec(&bnx2i_conn->ep->num_active_cmds);
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_cicqe_out:
20578c2ecf20Sopenharmony_ci		/* clear out in production version only, till beta keep opcode
20588c2ecf20Sopenharmony_ci		 * field intact, will be helpful in debugging (context dump)
20598c2ecf20Sopenharmony_ci		 * nopin->op_code = 0;
20608c2ecf20Sopenharmony_ci		 */
20618c2ecf20Sopenharmony_ci		cqe_cnt++;
20628c2ecf20Sopenharmony_ci		qp->cqe_exp_seq_sn++;
20638c2ecf20Sopenharmony_ci		if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
20648c2ecf20Sopenharmony_ci			qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci		if (qp->cq_cons_qe == qp->cq_last_qe) {
20678c2ecf20Sopenharmony_ci			qp->cq_cons_qe = qp->cq_first_qe;
20688c2ecf20Sopenharmony_ci			qp->cq_cons_idx = 0;
20698c2ecf20Sopenharmony_ci		} else {
20708c2ecf20Sopenharmony_ci			qp->cq_cons_qe++;
20718c2ecf20Sopenharmony_ci			qp->cq_cons_idx++;
20728c2ecf20Sopenharmony_ci		}
20738c2ecf20Sopenharmony_ci	}
20748c2ecf20Sopenharmony_ciout:
20758c2ecf20Sopenharmony_ci	return cqe_cnt;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/**
20798c2ecf20Sopenharmony_ci * bnx2i_fastpath_notification - process global event queue (KCQ)
20808c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
20818c2ecf20Sopenharmony_ci * @new_cqe_kcqe:	pointer to newly DMA'ed KCQE entry
20828c2ecf20Sopenharmony_ci *
20838c2ecf20Sopenharmony_ci * Fast path event notification handler, KCQ entry carries context id
20848c2ecf20Sopenharmony_ci *	of the connection that has 1 or more pending CQ entries
20858c2ecf20Sopenharmony_ci */
20868c2ecf20Sopenharmony_cistatic void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
20878c2ecf20Sopenharmony_ci					struct iscsi_kcqe *new_cqe_kcqe)
20888c2ecf20Sopenharmony_ci{
20898c2ecf20Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
20908c2ecf20Sopenharmony_ci	u32 iscsi_cid;
20918c2ecf20Sopenharmony_ci	int nxt_idx;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
20948c2ecf20Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	if (!bnx2i_conn) {
20978c2ecf20Sopenharmony_ci		printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
20988c2ecf20Sopenharmony_ci		return;
20998c2ecf20Sopenharmony_ci	}
21008c2ecf20Sopenharmony_ci	if (!bnx2i_conn->ep) {
21018c2ecf20Sopenharmony_ci		printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
21028c2ecf20Sopenharmony_ci		return;
21038c2ecf20Sopenharmony_ci	}
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	bnx2i_process_new_cqes(bnx2i_conn);
21068c2ecf20Sopenharmony_ci	nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep,
21078c2ecf20Sopenharmony_ci						CNIC_ARM_CQE_FP);
21088c2ecf20Sopenharmony_ci	if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn))
21098c2ecf20Sopenharmony_ci		bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
21108c2ecf20Sopenharmony_ci}
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci/**
21148c2ecf20Sopenharmony_ci * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE
21158c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
21168c2ecf20Sopenharmony_ci * @update_kcqe:	kcqe pointer
21178c2ecf20Sopenharmony_ci *
21188c2ecf20Sopenharmony_ci * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration
21198c2ecf20Sopenharmony_ci */
21208c2ecf20Sopenharmony_cistatic void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba,
21218c2ecf20Sopenharmony_ci					   struct iscsi_kcqe *update_kcqe)
21228c2ecf20Sopenharmony_ci{
21238c2ecf20Sopenharmony_ci	struct bnx2i_conn *conn;
21248c2ecf20Sopenharmony_ci	u32 iscsi_cid;
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	iscsi_cid = update_kcqe->iscsi_conn_id;
21278c2ecf20Sopenharmony_ci	conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	if (!conn) {
21308c2ecf20Sopenharmony_ci		printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid);
21318c2ecf20Sopenharmony_ci		return;
21328c2ecf20Sopenharmony_ci	}
21338c2ecf20Sopenharmony_ci	if (!conn->ep) {
21348c2ecf20Sopenharmony_ci		printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid);
21358c2ecf20Sopenharmony_ci		return;
21368c2ecf20Sopenharmony_ci	}
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	if (update_kcqe->completion_status) {
21398c2ecf20Sopenharmony_ci		printk(KERN_ALERT "request failed cid %x\n", iscsi_cid);
21408c2ecf20Sopenharmony_ci		conn->ep->state = EP_STATE_ULP_UPDATE_FAILED;
21418c2ecf20Sopenharmony_ci	} else
21428c2ecf20Sopenharmony_ci		conn->ep->state = EP_STATE_ULP_UPDATE_COMPL;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	wake_up_interruptible(&conn->ep->ofld_wait);
21458c2ecf20Sopenharmony_ci}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci/**
21498c2ecf20Sopenharmony_ci * bnx2i_recovery_que_add_conn - add connection to recovery queue
21508c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
21518c2ecf20Sopenharmony_ci * @bnx2i_conn:		iscsi connection
21528c2ecf20Sopenharmony_ci *
21538c2ecf20Sopenharmony_ci * Add connection to recovery queue and schedule adapter eh worker
21548c2ecf20Sopenharmony_ci */
21558c2ecf20Sopenharmony_cistatic void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba,
21568c2ecf20Sopenharmony_ci					struct bnx2i_conn *bnx2i_conn)
21578c2ecf20Sopenharmony_ci{
21588c2ecf20Sopenharmony_ci	iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data,
21598c2ecf20Sopenharmony_ci			   ISCSI_ERR_CONN_FAILED);
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci/**
21648c2ecf20Sopenharmony_ci * bnx2i_process_tcp_error - process error notification on a given connection
21658c2ecf20Sopenharmony_ci *
21668c2ecf20Sopenharmony_ci * @hba: 		adapter structure pointer
21678c2ecf20Sopenharmony_ci * @tcp_err: 		tcp error kcqe pointer
21688c2ecf20Sopenharmony_ci *
21698c2ecf20Sopenharmony_ci * handles tcp level error notifications from FW.
21708c2ecf20Sopenharmony_ci */
21718c2ecf20Sopenharmony_cistatic void bnx2i_process_tcp_error(struct bnx2i_hba *hba,
21728c2ecf20Sopenharmony_ci				    struct iscsi_kcqe *tcp_err)
21738c2ecf20Sopenharmony_ci{
21748c2ecf20Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
21758c2ecf20Sopenharmony_ci	u32 iscsi_cid;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	iscsi_cid = tcp_err->iscsi_conn_id;
21788c2ecf20Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	if (!bnx2i_conn) {
21818c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
21828c2ecf20Sopenharmony_ci		return;
21838c2ecf20Sopenharmony_ci	}
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n",
21868c2ecf20Sopenharmony_ci			  iscsi_cid, tcp_err->completion_status);
21878c2ecf20Sopenharmony_ci	bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci/**
21928c2ecf20Sopenharmony_ci * bnx2i_process_iscsi_error - process error notification on a given connection
21938c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
21948c2ecf20Sopenharmony_ci * @iscsi_err:		iscsi error kcqe pointer
21958c2ecf20Sopenharmony_ci *
21968c2ecf20Sopenharmony_ci * handles iscsi error notifications from the FW. Firmware based in initial
21978c2ecf20Sopenharmony_ci *	handshake classifies iscsi protocol / TCP rfc violation into either
21988c2ecf20Sopenharmony_ci *	warning or error indications. If indication is of "Error" type, driver
21998c2ecf20Sopenharmony_ci *	will initiate session recovery for that connection/session. For
22008c2ecf20Sopenharmony_ci *	"Warning" type indication, driver will put out a system log message
22018c2ecf20Sopenharmony_ci *	(there will be only one message for each type for the life of the
22028c2ecf20Sopenharmony_ci *	session, this is to avoid un-necessarily overloading the system)
22038c2ecf20Sopenharmony_ci */
22048c2ecf20Sopenharmony_cistatic void bnx2i_process_iscsi_error(struct bnx2i_hba *hba,
22058c2ecf20Sopenharmony_ci				      struct iscsi_kcqe *iscsi_err)
22068c2ecf20Sopenharmony_ci{
22078c2ecf20Sopenharmony_ci	struct bnx2i_conn *bnx2i_conn;
22088c2ecf20Sopenharmony_ci	u32 iscsi_cid;
22098c2ecf20Sopenharmony_ci	char warn_notice[] = "iscsi_warning";
22108c2ecf20Sopenharmony_ci	char error_notice[] = "iscsi_error";
22118c2ecf20Sopenharmony_ci	char additional_notice[64];
22128c2ecf20Sopenharmony_ci	char *message;
22138c2ecf20Sopenharmony_ci	int need_recovery;
22148c2ecf20Sopenharmony_ci	u64 err_mask64;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	iscsi_cid = iscsi_err->iscsi_conn_id;
22178c2ecf20Sopenharmony_ci	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
22188c2ecf20Sopenharmony_ci	if (!bnx2i_conn) {
22198c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
22208c2ecf20Sopenharmony_ci		return;
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	err_mask64 = (0x1ULL << iscsi_err->completion_status);
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	if (err_mask64 & iscsi_error_mask) {
22268c2ecf20Sopenharmony_ci		need_recovery = 0;
22278c2ecf20Sopenharmony_ci		message = warn_notice;
22288c2ecf20Sopenharmony_ci	} else {
22298c2ecf20Sopenharmony_ci		need_recovery = 1;
22308c2ecf20Sopenharmony_ci		message = error_notice;
22318c2ecf20Sopenharmony_ci	}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	switch (iscsi_err->completion_status) {
22348c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR:
22358c2ecf20Sopenharmony_ci		strcpy(additional_notice, "hdr digest err");
22368c2ecf20Sopenharmony_ci		break;
22378c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR:
22388c2ecf20Sopenharmony_ci		strcpy(additional_notice, "data digest err");
22398c2ecf20Sopenharmony_ci		break;
22408c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE:
22418c2ecf20Sopenharmony_ci		strcpy(additional_notice, "wrong opcode rcvd");
22428c2ecf20Sopenharmony_ci		break;
22438c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN:
22448c2ecf20Sopenharmony_ci		strcpy(additional_notice, "AHS len > 0 rcvd");
22458c2ecf20Sopenharmony_ci		break;
22468c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT:
22478c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid ITT rcvd");
22488c2ecf20Sopenharmony_ci		break;
22498c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN:
22508c2ecf20Sopenharmony_ci		strcpy(additional_notice, "wrong StatSN rcvd");
22518c2ecf20Sopenharmony_ci		break;
22528c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN:
22538c2ecf20Sopenharmony_ci		strcpy(additional_notice, "wrong DataSN rcvd");
22548c2ecf20Sopenharmony_ci		break;
22558c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T:
22568c2ecf20Sopenharmony_ci		strcpy(additional_notice, "pend R2T violation");
22578c2ecf20Sopenharmony_ci		break;
22588c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0:
22598c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, UO");
22608c2ecf20Sopenharmony_ci		break;
22618c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1:
22628c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U1");
22638c2ecf20Sopenharmony_ci		break;
22648c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2:
22658c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U2");
22668c2ecf20Sopenharmony_ci		break;
22678c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3:
22688c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U3");
22698c2ecf20Sopenharmony_ci		break;
22708c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4:
22718c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U4");
22728c2ecf20Sopenharmony_ci		break;
22738c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5:
22748c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U5");
22758c2ecf20Sopenharmony_ci		break;
22768c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6:
22778c2ecf20Sopenharmony_ci		strcpy(additional_notice, "ERL0, U6");
22788c2ecf20Sopenharmony_ci		break;
22798c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN:
22808c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid resi len");
22818c2ecf20Sopenharmony_ci		break;
22828c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN:
22838c2ecf20Sopenharmony_ci		strcpy(additional_notice, "MRDSL violation");
22848c2ecf20Sopenharmony_ci		break;
22858c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO:
22868c2ecf20Sopenharmony_ci		strcpy(additional_notice, "F-bit not set");
22878c2ecf20Sopenharmony_ci		break;
22888c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV:
22898c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid TTT");
22908c2ecf20Sopenharmony_ci		break;
22918c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN:
22928c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid DataSN");
22938c2ecf20Sopenharmony_ci		break;
22948c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN:
22958c2ecf20Sopenharmony_ci		strcpy(additional_notice, "burst len violation");
22968c2ecf20Sopenharmony_ci		break;
22978c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF:
22988c2ecf20Sopenharmony_ci		strcpy(additional_notice, "buf offset violation");
22998c2ecf20Sopenharmony_ci		break;
23008c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN:
23018c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid LUN field");
23028c2ecf20Sopenharmony_ci		break;
23038c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN:
23048c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid R2TSN field");
23058c2ecf20Sopenharmony_ci		break;
23068c2ecf20Sopenharmony_ci#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0 	\
23078c2ecf20Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0
23088c2ecf20Sopenharmony_ci	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0:
23098c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid cmd len1");
23108c2ecf20Sopenharmony_ci		break;
23118c2ecf20Sopenharmony_ci#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1 	\
23128c2ecf20Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1
23138c2ecf20Sopenharmony_ci	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1:
23148c2ecf20Sopenharmony_ci		strcpy(additional_notice, "invalid cmd len2");
23158c2ecf20Sopenharmony_ci		break;
23168c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED:
23178c2ecf20Sopenharmony_ci		strcpy(additional_notice,
23188c2ecf20Sopenharmony_ci		       "pend r2t exceeds MaxOutstandingR2T value");
23198c2ecf20Sopenharmony_ci		break;
23208c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV:
23218c2ecf20Sopenharmony_ci		strcpy(additional_notice, "TTT is rsvd");
23228c2ecf20Sopenharmony_ci		break;
23238c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN:
23248c2ecf20Sopenharmony_ci		strcpy(additional_notice, "MBL violation");
23258c2ecf20Sopenharmony_ci		break;
23268c2ecf20Sopenharmony_ci#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO 	\
23278c2ecf20Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO
23288c2ecf20Sopenharmony_ci	case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO:
23298c2ecf20Sopenharmony_ci		strcpy(additional_notice, "data seg len != 0");
23308c2ecf20Sopenharmony_ci		break;
23318c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN:
23328c2ecf20Sopenharmony_ci		strcpy(additional_notice, "reject pdu len error");
23338c2ecf20Sopenharmony_ci		break;
23348c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN:
23358c2ecf20Sopenharmony_ci		strcpy(additional_notice, "async pdu len error");
23368c2ecf20Sopenharmony_ci		break;
23378c2ecf20Sopenharmony_ci	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN:
23388c2ecf20Sopenharmony_ci		strcpy(additional_notice, "nopin pdu len error");
23398c2ecf20Sopenharmony_ci		break;
23408c2ecf20Sopenharmony_ci#define BNX2_ERR_PEND_R2T_IN_CLEANUP			\
23418c2ecf20Sopenharmony_ci	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP
23428c2ecf20Sopenharmony_ci	case BNX2_ERR_PEND_R2T_IN_CLEANUP:
23438c2ecf20Sopenharmony_ci		strcpy(additional_notice, "pend r2t in cleanup");
23448c2ecf20Sopenharmony_ci		break;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT:
23478c2ecf20Sopenharmony_ci		strcpy(additional_notice, "IP fragments rcvd");
23488c2ecf20Sopenharmony_ci		break;
23498c2ecf20Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS:
23508c2ecf20Sopenharmony_ci		strcpy(additional_notice, "IP options error");
23518c2ecf20Sopenharmony_ci		break;
23528c2ecf20Sopenharmony_ci	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG:
23538c2ecf20Sopenharmony_ci		strcpy(additional_notice, "urgent flag error");
23548c2ecf20Sopenharmony_ci		break;
23558c2ecf20Sopenharmony_ci	default:
23568c2ecf20Sopenharmony_ci		printk(KERN_ALERT "iscsi_err - unknown err %x\n",
23578c2ecf20Sopenharmony_ci				  iscsi_err->completion_status);
23588c2ecf20Sopenharmony_ci	}
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	if (need_recovery) {
23618c2ecf20Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT,
23628c2ecf20Sopenharmony_ci				  bnx2i_conn->cls_conn->dd_data,
23638c2ecf20Sopenharmony_ci				  "bnx2i: %s - %s\n",
23648c2ecf20Sopenharmony_ci				  message, additional_notice);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci		iscsi_conn_printk(KERN_ALERT,
23678c2ecf20Sopenharmony_ci				  bnx2i_conn->cls_conn->dd_data,
23688c2ecf20Sopenharmony_ci				  "conn_err - hostno %d conn %p, "
23698c2ecf20Sopenharmony_ci				  "iscsi_cid %x cid %x\n",
23708c2ecf20Sopenharmony_ci				  bnx2i_conn->hba->shost->host_no,
23718c2ecf20Sopenharmony_ci				  bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid,
23728c2ecf20Sopenharmony_ci				  bnx2i_conn->ep->ep_cid);
23738c2ecf20Sopenharmony_ci		bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
23748c2ecf20Sopenharmony_ci	} else
23758c2ecf20Sopenharmony_ci		if (!test_and_set_bit(iscsi_err->completion_status,
23768c2ecf20Sopenharmony_ci				      (void *) &bnx2i_conn->violation_notified))
23778c2ecf20Sopenharmony_ci			iscsi_conn_printk(KERN_ALERT,
23788c2ecf20Sopenharmony_ci					  bnx2i_conn->cls_conn->dd_data,
23798c2ecf20Sopenharmony_ci					  "bnx2i: %s - %s\n",
23808c2ecf20Sopenharmony_ci					  message, additional_notice);
23818c2ecf20Sopenharmony_ci}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci/**
23858c2ecf20Sopenharmony_ci * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion
23868c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
23878c2ecf20Sopenharmony_ci * @conn_destroy:	conn destroy kcqe pointer
23888c2ecf20Sopenharmony_ci *
23898c2ecf20Sopenharmony_ci * handles connection destroy completion request.
23908c2ecf20Sopenharmony_ci */
23918c2ecf20Sopenharmony_cistatic void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
23928c2ecf20Sopenharmony_ci					    struct iscsi_kcqe *conn_destroy)
23938c2ecf20Sopenharmony_ci{
23948c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id);
23978c2ecf20Sopenharmony_ci	if (!ep) {
23988c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending "
23998c2ecf20Sopenharmony_ci				  "offload request, unexpected completion\n");
24008c2ecf20Sopenharmony_ci		return;
24018c2ecf20Sopenharmony_ci	}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	if (hba != ep->hba) {
24048c2ecf20Sopenharmony_ci		printk(KERN_ALERT "conn destroy- error hba mis-match\n");
24058c2ecf20Sopenharmony_ci		return;
24068c2ecf20Sopenharmony_ci	}
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	if (conn_destroy->completion_status) {
24098c2ecf20Sopenharmony_ci		printk(KERN_ALERT "conn_destroy_cmpl: op failed\n");
24108c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_FAILED;
24118c2ecf20Sopenharmony_ci	} else
24128c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CLEANUP_CMPL;
24138c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
24148c2ecf20Sopenharmony_ci}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci/**
24188c2ecf20Sopenharmony_ci * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion
24198c2ecf20Sopenharmony_ci * @hba:		adapter structure pointer
24208c2ecf20Sopenharmony_ci * @ofld_kcqe:		conn offload kcqe pointer
24218c2ecf20Sopenharmony_ci *
24228c2ecf20Sopenharmony_ci * handles initial connection offload completion, ep_connect() thread is
24238c2ecf20Sopenharmony_ci *	woken-up to continue with LLP connect process
24248c2ecf20Sopenharmony_ci */
24258c2ecf20Sopenharmony_cistatic void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
24268c2ecf20Sopenharmony_ci				    struct iscsi_kcqe *ofld_kcqe)
24278c2ecf20Sopenharmony_ci{
24288c2ecf20Sopenharmony_ci	u32 cid_addr;
24298c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id);
24328c2ecf20Sopenharmony_ci	if (!ep) {
24338c2ecf20Sopenharmony_ci		printk(KERN_ALERT "ofld_cmpl: no pend offload request\n");
24348c2ecf20Sopenharmony_ci		return;
24358c2ecf20Sopenharmony_ci	}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	if (hba != ep->hba) {
24388c2ecf20Sopenharmony_ci		printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n");
24398c2ecf20Sopenharmony_ci		return;
24408c2ecf20Sopenharmony_ci	}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (ofld_kcqe->completion_status) {
24438c2ecf20Sopenharmony_ci		ep->state = EP_STATE_OFLD_FAILED;
24448c2ecf20Sopenharmony_ci		if (ofld_kcqe->completion_status ==
24458c2ecf20Sopenharmony_ci		    ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
24468c2ecf20Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable "
24478c2ecf20Sopenharmony_ci				"to allocate iSCSI context resources\n",
24488c2ecf20Sopenharmony_ci				hba->netdev->name);
24498c2ecf20Sopenharmony_ci		else if (ofld_kcqe->completion_status ==
24508c2ecf20Sopenharmony_ci			 ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE)
24518c2ecf20Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
24528c2ecf20Sopenharmony_ci				"opcode\n", hba->netdev->name);
24538c2ecf20Sopenharmony_ci		else if (ofld_kcqe->completion_status ==
24548c2ecf20Sopenharmony_ci			 ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
24558c2ecf20Sopenharmony_ci			/* error status code valid only for 5771x chipset */
24568c2ecf20Sopenharmony_ci			ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
24578c2ecf20Sopenharmony_ci		else
24588c2ecf20Sopenharmony_ci			printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
24598c2ecf20Sopenharmony_ci				"error code %d\n", hba->netdev->name,
24608c2ecf20Sopenharmony_ci				ofld_kcqe->completion_status);
24618c2ecf20Sopenharmony_ci	} else {
24628c2ecf20Sopenharmony_ci		ep->state = EP_STATE_OFLD_COMPL;
24638c2ecf20Sopenharmony_ci		cid_addr = ofld_kcqe->iscsi_conn_context_id;
24648c2ecf20Sopenharmony_ci		ep->ep_cid = cid_addr;
24658c2ecf20Sopenharmony_ci		ep->qp.ctx_base = NULL;
24668c2ecf20Sopenharmony_ci	}
24678c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
24688c2ecf20Sopenharmony_ci}
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci/**
24718c2ecf20Sopenharmony_ci * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE
24728c2ecf20Sopenharmony_ci * @context:		adapter structure pointer
24738c2ecf20Sopenharmony_ci * @kcqe:		kcqe pointer
24748c2ecf20Sopenharmony_ci * @num_cqe:		number of kcqes to process
24758c2ecf20Sopenharmony_ci *
24768c2ecf20Sopenharmony_ci * Generic KCQ event handler/dispatcher
24778c2ecf20Sopenharmony_ci */
24788c2ecf20Sopenharmony_cistatic void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[],
24798c2ecf20Sopenharmony_ci				u32 num_cqe)
24808c2ecf20Sopenharmony_ci{
24818c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = context;
24828c2ecf20Sopenharmony_ci	int i = 0;
24838c2ecf20Sopenharmony_ci	struct iscsi_kcqe *ikcqe = NULL;
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	while (i < num_cqe) {
24868c2ecf20Sopenharmony_ci		ikcqe = (struct iscsi_kcqe *) kcqe[i++];
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci		if (ikcqe->op_code ==
24898c2ecf20Sopenharmony_ci		    ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION)
24908c2ecf20Sopenharmony_ci			bnx2i_fastpath_notification(hba, ikcqe);
24918c2ecf20Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN)
24928c2ecf20Sopenharmony_ci			bnx2i_process_ofld_cmpl(hba, ikcqe);
24938c2ecf20Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN)
24948c2ecf20Sopenharmony_ci			bnx2i_process_update_conn_cmpl(hba, ikcqe);
24958c2ecf20Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) {
24968c2ecf20Sopenharmony_ci			if (ikcqe->completion_status !=
24978c2ecf20Sopenharmony_ci			    ISCSI_KCQE_COMPLETION_STATUS_SUCCESS)
24988c2ecf20Sopenharmony_ci				bnx2i_iscsi_license_error(hba, ikcqe->\
24998c2ecf20Sopenharmony_ci							  completion_status);
25008c2ecf20Sopenharmony_ci			else {
25018c2ecf20Sopenharmony_ci				set_bit(ADAPTER_STATE_UP, &hba->adapter_state);
25028c2ecf20Sopenharmony_ci				bnx2i_get_link_state(hba);
25038c2ecf20Sopenharmony_ci				printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: "
25048c2ecf20Sopenharmony_ci						 "ISCSI_INIT passed\n",
25058c2ecf20Sopenharmony_ci						 (u8)hba->pcidev->bus->number,
25068c2ecf20Sopenharmony_ci						 hba->pci_devno,
25078c2ecf20Sopenharmony_ci						 (u8)hba->pci_func);
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci			}
25118c2ecf20Sopenharmony_ci		} else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN)
25128c2ecf20Sopenharmony_ci			bnx2i_process_conn_destroy_cmpl(hba, ikcqe);
25138c2ecf20Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR)
25148c2ecf20Sopenharmony_ci			bnx2i_process_iscsi_error(hba, ikcqe);
25158c2ecf20Sopenharmony_ci		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR)
25168c2ecf20Sopenharmony_ci			bnx2i_process_tcp_error(hba, ikcqe);
25178c2ecf20Sopenharmony_ci		else
25188c2ecf20Sopenharmony_ci			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
25198c2ecf20Sopenharmony_ci					  ikcqe->op_code);
25208c2ecf20Sopenharmony_ci	}
25218c2ecf20Sopenharmony_ci}
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci/**
25258c2ecf20Sopenharmony_ci * bnx2i_indicate_netevent - Generic netdev event handler
25268c2ecf20Sopenharmony_ci * @context:	adapter structure pointer
25278c2ecf20Sopenharmony_ci * @event:	event type
25288c2ecf20Sopenharmony_ci * @vlan_id:	vlans id - associated vlan id with this event
25298c2ecf20Sopenharmony_ci *
25308c2ecf20Sopenharmony_ci * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
25318c2ecf20Sopenharmony_ci *	NETDEV_GOING_DOWN and NETDEV_CHANGE
25328c2ecf20Sopenharmony_ci */
25338c2ecf20Sopenharmony_cistatic void bnx2i_indicate_netevent(void *context, unsigned long event,
25348c2ecf20Sopenharmony_ci				    u16 vlan_id)
25358c2ecf20Sopenharmony_ci{
25368c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = context;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	/* Ignore all netevent coming from vlans */
25398c2ecf20Sopenharmony_ci	if (vlan_id != 0)
25408c2ecf20Sopenharmony_ci		return;
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	switch (event) {
25438c2ecf20Sopenharmony_ci	case NETDEV_UP:
25448c2ecf20Sopenharmony_ci		if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
25458c2ecf20Sopenharmony_ci			bnx2i_send_fw_iscsi_init_msg(hba);
25468c2ecf20Sopenharmony_ci		break;
25478c2ecf20Sopenharmony_ci	case NETDEV_DOWN:
25488c2ecf20Sopenharmony_ci		clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
25498c2ecf20Sopenharmony_ci		clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
25508c2ecf20Sopenharmony_ci		break;
25518c2ecf20Sopenharmony_ci	case NETDEV_GOING_DOWN:
25528c2ecf20Sopenharmony_ci		set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
25538c2ecf20Sopenharmony_ci		iscsi_host_for_each_session(hba->shost,
25548c2ecf20Sopenharmony_ci					    bnx2i_drop_session);
25558c2ecf20Sopenharmony_ci		break;
25568c2ecf20Sopenharmony_ci	case NETDEV_CHANGE:
25578c2ecf20Sopenharmony_ci		bnx2i_get_link_state(hba);
25588c2ecf20Sopenharmony_ci		break;
25598c2ecf20Sopenharmony_ci	default:
25608c2ecf20Sopenharmony_ci		;
25618c2ecf20Sopenharmony_ci	}
25628c2ecf20Sopenharmony_ci}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci/**
25668c2ecf20Sopenharmony_ci * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion
25678c2ecf20Sopenharmony_ci * @cm_sk: 		cnic sock structure pointer
25688c2ecf20Sopenharmony_ci *
25698c2ecf20Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
25708c2ecf20Sopenharmony_ci *	indicate completion of option-2 TCP connect request.
25718c2ecf20Sopenharmony_ci */
25728c2ecf20Sopenharmony_cistatic void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk)
25738c2ecf20Sopenharmony_ci{
25748c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
25778c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CONNECT_FAILED;
25788c2ecf20Sopenharmony_ci	else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags))
25798c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CONNECT_COMPL;
25808c2ecf20Sopenharmony_ci	else
25818c2ecf20Sopenharmony_ci		ep->state = EP_STATE_CONNECT_FAILED;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
25848c2ecf20Sopenharmony_ci}
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci/**
25888c2ecf20Sopenharmony_ci * bnx2i_cm_close_cmpl - process tcp conn close completion
25898c2ecf20Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
25908c2ecf20Sopenharmony_ci *
25918c2ecf20Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
25928c2ecf20Sopenharmony_ci *	indicate completion of option-2 graceful TCP connect shutdown
25938c2ecf20Sopenharmony_ci */
25948c2ecf20Sopenharmony_cistatic void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk)
25958c2ecf20Sopenharmony_ci{
25968c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	ep->state = EP_STATE_DISCONN_COMPL;
25998c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
26008c2ecf20Sopenharmony_ci}
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci/**
26048c2ecf20Sopenharmony_ci * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion
26058c2ecf20Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
26068c2ecf20Sopenharmony_ci *
26078c2ecf20Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
26088c2ecf20Sopenharmony_ci *	indicate completion of option-2 abortive TCP connect termination
26098c2ecf20Sopenharmony_ci */
26108c2ecf20Sopenharmony_cistatic void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk)
26118c2ecf20Sopenharmony_ci{
26128c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	ep->state = EP_STATE_DISCONN_COMPL;
26158c2ecf20Sopenharmony_ci	wake_up_interruptible(&ep->ofld_wait);
26168c2ecf20Sopenharmony_ci}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci/**
26208c2ecf20Sopenharmony_ci * bnx2i_cm_remote_close - process received TCP FIN
26218c2ecf20Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
26228c2ecf20Sopenharmony_ci *
26238c2ecf20Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to indicate
26248c2ecf20Sopenharmony_ci *	async TCP events such as FIN
26258c2ecf20Sopenharmony_ci */
26268c2ecf20Sopenharmony_cistatic void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
26278c2ecf20Sopenharmony_ci{
26288c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	ep->state = EP_STATE_TCP_FIN_RCVD;
26318c2ecf20Sopenharmony_ci	if (ep->conn)
26328c2ecf20Sopenharmony_ci		bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
26338c2ecf20Sopenharmony_ci}
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci/**
26368c2ecf20Sopenharmony_ci * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup
26378c2ecf20Sopenharmony_ci * @cm_sk:	cnic sock structure pointer
26388c2ecf20Sopenharmony_ci *
26398c2ecf20Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to
26408c2ecf20Sopenharmony_ci *	indicate async TCP events (RST) sent by the peer.
26418c2ecf20Sopenharmony_ci */
26428c2ecf20Sopenharmony_cistatic void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
26438c2ecf20Sopenharmony_ci{
26448c2ecf20Sopenharmony_ci	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
26458c2ecf20Sopenharmony_ci	u32 old_state = ep->state;
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci	ep->state = EP_STATE_TCP_RST_RCVD;
26488c2ecf20Sopenharmony_ci	if (old_state == EP_STATE_DISCONN_START)
26498c2ecf20Sopenharmony_ci		wake_up_interruptible(&ep->ofld_wait);
26508c2ecf20Sopenharmony_ci	else
26518c2ecf20Sopenharmony_ci		if (ep->conn)
26528c2ecf20Sopenharmony_ci			bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
26538c2ecf20Sopenharmony_ci}
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_cistatic int bnx2i_send_nl_mesg(void *context, u32 msg_type,
26578c2ecf20Sopenharmony_ci			      char *buf, u16 buflen)
26588c2ecf20Sopenharmony_ci{
26598c2ecf20Sopenharmony_ci	struct bnx2i_hba *hba = context;
26608c2ecf20Sopenharmony_ci	int rc;
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	if (!hba)
26638c2ecf20Sopenharmony_ci		return -ENODEV;
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
26668c2ecf20Sopenharmony_ci				msg_type, buf, buflen);
26678c2ecf20Sopenharmony_ci	if (rc)
26688c2ecf20Sopenharmony_ci		printk(KERN_ALERT "bnx2i: private nl message send error\n");
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	return rc;
26718c2ecf20Sopenharmony_ci}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci/*
26758c2ecf20Sopenharmony_ci * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure
26768c2ecf20Sopenharmony_ci *			carrying callback function pointers
26778c2ecf20Sopenharmony_ci */
26788c2ecf20Sopenharmony_cistruct cnic_ulp_ops bnx2i_cnic_cb = {
26798c2ecf20Sopenharmony_ci	.cnic_init = bnx2i_ulp_init,
26808c2ecf20Sopenharmony_ci	.cnic_exit = bnx2i_ulp_exit,
26818c2ecf20Sopenharmony_ci	.cnic_start = bnx2i_start,
26828c2ecf20Sopenharmony_ci	.cnic_stop = bnx2i_stop,
26838c2ecf20Sopenharmony_ci	.indicate_kcqes = bnx2i_indicate_kcqe,
26848c2ecf20Sopenharmony_ci	.indicate_netevent = bnx2i_indicate_netevent,
26858c2ecf20Sopenharmony_ci	.cm_connect_complete = bnx2i_cm_connect_cmpl,
26868c2ecf20Sopenharmony_ci	.cm_close_complete = bnx2i_cm_close_cmpl,
26878c2ecf20Sopenharmony_ci	.cm_abort_complete = bnx2i_cm_abort_cmpl,
26888c2ecf20Sopenharmony_ci	.cm_remote_close = bnx2i_cm_remote_close,
26898c2ecf20Sopenharmony_ci	.cm_remote_abort = bnx2i_cm_remote_abort,
26908c2ecf20Sopenharmony_ci	.iscsi_nl_send_msg = bnx2i_send_nl_mesg,
26918c2ecf20Sopenharmony_ci	.cnic_get_stats = bnx2i_get_stats,
26928c2ecf20Sopenharmony_ci	.owner = THIS_MODULE
26938c2ecf20Sopenharmony_ci};
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci/**
26978c2ecf20Sopenharmony_ci * bnx2i_map_ep_dbell_regs - map connection doorbell registers
26988c2ecf20Sopenharmony_ci * @ep: bnx2i endpoint
26998c2ecf20Sopenharmony_ci *
27008c2ecf20Sopenharmony_ci * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these
27018c2ecf20Sopenharmony_ci *	register in BAR #0. Whereas in 57710 these register are accessed by
27028c2ecf20Sopenharmony_ci *	mapping BAR #1
27038c2ecf20Sopenharmony_ci */
27048c2ecf20Sopenharmony_ciint bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
27058c2ecf20Sopenharmony_ci{
27068c2ecf20Sopenharmony_ci	u32 cid_num;
27078c2ecf20Sopenharmony_ci	u32 reg_off;
27088c2ecf20Sopenharmony_ci	u32 first_l4l5;
27098c2ecf20Sopenharmony_ci	u32 ctx_sz;
27108c2ecf20Sopenharmony_ci	u32 config2;
27118c2ecf20Sopenharmony_ci	resource_size_t reg_base;
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	cid_num = bnx2i_get_cid_num(ep);
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
27168c2ecf20Sopenharmony_ci		reg_base = pci_resource_start(ep->hba->pcidev,
27178c2ecf20Sopenharmony_ci					      BNX2X_DOORBELL_PCI_BAR);
27188c2ecf20Sopenharmony_ci		reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF);
27198c2ecf20Sopenharmony_ci		ep->qp.ctx_base = ioremap(reg_base + reg_off, 4);
27208c2ecf20Sopenharmony_ci		if (!ep->qp.ctx_base)
27218c2ecf20Sopenharmony_ci			return -ENOMEM;
27228c2ecf20Sopenharmony_ci		goto arm_cq;
27238c2ecf20Sopenharmony_ci	}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
27268c2ecf20Sopenharmony_ci	    (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
27278c2ecf20Sopenharmony_ci		config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
27288c2ecf20Sopenharmony_ci		first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5;
27298c2ecf20Sopenharmony_ci		ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
27308c2ecf20Sopenharmony_ci		if (ctx_sz)
27318c2ecf20Sopenharmony_ci			reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
27328c2ecf20Sopenharmony_ci				  + BNX2I_570X_PAGE_SIZE_DEFAULT *
27338c2ecf20Sopenharmony_ci				  (((cid_num - first_l4l5) / ctx_sz) + 256);
27348c2ecf20Sopenharmony_ci		else
27358c2ecf20Sopenharmony_ci			reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
27368c2ecf20Sopenharmony_ci	} else
27378c2ecf20Sopenharmony_ci		/* 5709 device in normal node and 5706/5708 devices */
27388c2ecf20Sopenharmony_ci		reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	ep->qp.ctx_base = ioremap(ep->hba->reg_base + reg_off,
27418c2ecf20Sopenharmony_ci					  MB_KERNEL_CTX_SIZE);
27428c2ecf20Sopenharmony_ci	if (!ep->qp.ctx_base)
27438c2ecf20Sopenharmony_ci		return -ENOMEM;
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ciarm_cq:
27468c2ecf20Sopenharmony_ci	bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE);
27478c2ecf20Sopenharmony_ci	return 0;
27488c2ecf20Sopenharmony_ci}
2749