162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI
362306a36Sopenharmony_ci * Host Bus Adapters. Refer to the README file included with this package
462306a36Sopenharmony_ci * for driver version and adapter compatibility.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2018 Broadcom. All Rights Reserved.
762306a36Sopenharmony_ci * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
1062306a36Sopenharmony_ci * under the terms of version 2 of the GNU General Public License as published
1162306a36Sopenharmony_ci * by the Free Software Foundation.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful. ALL EXPRESS
1462306a36Sopenharmony_ci * OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
1562306a36Sopenharmony_ci * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
1662306a36Sopenharmony_ci * OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH
1762306a36Sopenharmony_ci * DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
1862306a36Sopenharmony_ci * See the GNU General Public License for more details, a copy of which
1962306a36Sopenharmony_ci * can be found in the file COPYING included with this package.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Contact Information:
2262306a36Sopenharmony_ci * linux-drivers@broadcom.com
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/bsg-lib.h>
2762306a36Sopenharmony_ci#include <scsi/scsi_transport_iscsi.h>
2862306a36Sopenharmony_ci#include <scsi/scsi_bsg_iscsi.h>
2962306a36Sopenharmony_ci#include "be_mgmt.h"
3062306a36Sopenharmony_ci#include "be_iscsi.h"
3162306a36Sopenharmony_ci#include "be_main.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciunsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
3462306a36Sopenharmony_ci					 struct beiscsi_hba *phba,
3562306a36Sopenharmony_ci					 struct bsg_job *job,
3662306a36Sopenharmony_ci					 struct be_dma_mem *nonemb_cmd)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
3962306a36Sopenharmony_ci	struct be_sge *mcc_sge;
4062306a36Sopenharmony_ci	unsigned int tag = 0;
4162306a36Sopenharmony_ci	struct iscsi_bsg_request *bsg_req = job->request;
4262306a36Sopenharmony_ci	struct be_bsg_vendor_cmd *req = nonemb_cmd->va;
4362306a36Sopenharmony_ci	unsigned short region, sector_size, sector, offset;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	nonemb_cmd->size = job->request_payload.payload_len;
4662306a36Sopenharmony_ci	memset(nonemb_cmd->va, 0, nonemb_cmd->size);
4762306a36Sopenharmony_ci	region =  bsg_req->rqst_data.h_vendor.vendor_cmd[1];
4862306a36Sopenharmony_ci	sector_size =  bsg_req->rqst_data.h_vendor.vendor_cmd[2];
4962306a36Sopenharmony_ci	sector =  bsg_req->rqst_data.h_vendor.vendor_cmd[3];
5062306a36Sopenharmony_ci	offset =  bsg_req->rqst_data.h_vendor.vendor_cmd[4];
5162306a36Sopenharmony_ci	req->region = region;
5262306a36Sopenharmony_ci	req->sector = sector;
5362306a36Sopenharmony_ci	req->offset = offset;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ctrl->mbox_lock))
5662306a36Sopenharmony_ci		return 0;
5762306a36Sopenharmony_ci	switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
5862306a36Sopenharmony_ci	case BEISCSI_WRITE_FLASH:
5962306a36Sopenharmony_ci		offset = sector * sector_size + offset;
6062306a36Sopenharmony_ci		be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
6162306a36Sopenharmony_ci				   OPCODE_COMMON_WRITE_FLASH, sizeof(*req));
6262306a36Sopenharmony_ci		sg_copy_to_buffer(job->request_payload.sg_list,
6362306a36Sopenharmony_ci				  job->request_payload.sg_cnt,
6462306a36Sopenharmony_ci				  nonemb_cmd->va + offset, job->request_len);
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	case BEISCSI_READ_FLASH:
6762306a36Sopenharmony_ci		be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
6862306a36Sopenharmony_ci			   OPCODE_COMMON_READ_FLASH, sizeof(*req));
6962306a36Sopenharmony_ci		break;
7062306a36Sopenharmony_ci	default:
7162306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
7262306a36Sopenharmony_ci			    "BG_%d : Unsupported cmd = 0x%x\n\n",
7362306a36Sopenharmony_ci			    bsg_req->rqst_data.h_vendor.vendor_cmd[0]);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
7662306a36Sopenharmony_ci		return -EPERM;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
8062306a36Sopenharmony_ci	if (!wrb) {
8162306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
8262306a36Sopenharmony_ci		return 0;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	mcc_sge = nonembedded_sgl(wrb);
8662306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
8762306a36Sopenharmony_ci			   job->request_payload.sg_cnt);
8862306a36Sopenharmony_ci	mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
8962306a36Sopenharmony_ci	mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
9062306a36Sopenharmony_ci	mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
9562306a36Sopenharmony_ci	return tag;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/**
9962306a36Sopenharmony_ci * mgmt_open_connection()- Establish a TCP CXN
10062306a36Sopenharmony_ci * @phba: driver priv structure
10162306a36Sopenharmony_ci * @dst_addr: Destination Address
10262306a36Sopenharmony_ci * @beiscsi_ep: ptr to device endpoint struct
10362306a36Sopenharmony_ci * @nonemb_cmd: ptr to memory allocated for command
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * return
10662306a36Sopenharmony_ci *	Success: Tag number of the MBX Command issued
10762306a36Sopenharmony_ci *	Failure: Error code
10862306a36Sopenharmony_ci **/
10962306a36Sopenharmony_ciint mgmt_open_connection(struct beiscsi_hba *phba,
11062306a36Sopenharmony_ci			 struct sockaddr *dst_addr,
11162306a36Sopenharmony_ci			 struct beiscsi_endpoint *beiscsi_ep,
11262306a36Sopenharmony_ci			 struct be_dma_mem *nonemb_cmd)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct hwi_controller *phwi_ctrlr;
11562306a36Sopenharmony_ci	struct hwi_context_memory *phwi_context;
11662306a36Sopenharmony_ci	struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr;
11762306a36Sopenharmony_ci	struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr;
11862306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
11962306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
12062306a36Sopenharmony_ci	struct tcp_connect_and_offload_in_v1 *req;
12162306a36Sopenharmony_ci	unsigned short def_hdr_id;
12262306a36Sopenharmony_ci	unsigned short def_data_id;
12362306a36Sopenharmony_ci	struct phys_addr template_address = { 0, 0 };
12462306a36Sopenharmony_ci	struct phys_addr *ptemplate_address;
12562306a36Sopenharmony_ci	unsigned int tag = 0;
12662306a36Sopenharmony_ci	unsigned int i, ulp_num;
12762306a36Sopenharmony_ci	unsigned short cid = beiscsi_ep->ep_cid;
12862306a36Sopenharmony_ci	struct be_sge *sge;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (dst_addr->sa_family != PF_INET && dst_addr->sa_family != PF_INET6) {
13162306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
13262306a36Sopenharmony_ci			    "BG_%d : unknown addr family %d\n",
13362306a36Sopenharmony_ci			    dst_addr->sa_family);
13462306a36Sopenharmony_ci		return 0;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	phwi_ctrlr = phba->phwi_ctrlr;
13862306a36Sopenharmony_ci	phwi_context = phwi_ctrlr->phwi_ctxt;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	ulp_num = phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID(cid)].ulp_num;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba, ulp_num);
14362306a36Sopenharmony_ci	def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba, ulp_num);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	ptemplate_address = &template_address;
14662306a36Sopenharmony_ci	ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
14762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ctrl->mbox_lock))
14862306a36Sopenharmony_ci		return 0;
14962306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
15062306a36Sopenharmony_ci	if (!wrb) {
15162306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
15262306a36Sopenharmony_ci		return 0;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	sge = nonembedded_sgl(wrb);
15662306a36Sopenharmony_ci	req = nonemb_cmd->va;
15762306a36Sopenharmony_ci	memset(req, 0, sizeof(*req));
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
16062306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
16162306a36Sopenharmony_ci			   OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
16262306a36Sopenharmony_ci			   nonemb_cmd->size);
16362306a36Sopenharmony_ci	if (dst_addr->sa_family == PF_INET) {
16462306a36Sopenharmony_ci		__be32 s_addr = daddr_in->sin_addr.s_addr;
16562306a36Sopenharmony_ci		req->ip_address.ip_type = BEISCSI_IP_TYPE_V4;
16662306a36Sopenharmony_ci		req->ip_address.addr[0] = s_addr & 0x000000ff;
16762306a36Sopenharmony_ci		req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8;
16862306a36Sopenharmony_ci		req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16;
16962306a36Sopenharmony_ci		req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24;
17062306a36Sopenharmony_ci		req->tcp_port = ntohs(daddr_in->sin_port);
17162306a36Sopenharmony_ci		beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
17262306a36Sopenharmony_ci		beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
17362306a36Sopenharmony_ci		beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V4;
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		/* else its PF_INET6 family */
17662306a36Sopenharmony_ci		req->ip_address.ip_type = BEISCSI_IP_TYPE_V6;
17762306a36Sopenharmony_ci		memcpy(&req->ip_address.addr,
17862306a36Sopenharmony_ci		       &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
17962306a36Sopenharmony_ci		req->tcp_port = ntohs(daddr_in6->sin6_port);
18062306a36Sopenharmony_ci		beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
18162306a36Sopenharmony_ci		memcpy(&beiscsi_ep->dst6_addr,
18262306a36Sopenharmony_ci		       &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
18362306a36Sopenharmony_ci		beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V6;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	req->cid = cid;
18662306a36Sopenharmony_ci	i = phba->nxt_cqid++;
18762306a36Sopenharmony_ci	if (phba->nxt_cqid == phba->num_cpus)
18862306a36Sopenharmony_ci		phba->nxt_cqid = 0;
18962306a36Sopenharmony_ci	req->cq_id = phwi_context->be_cq[i].id;
19062306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
19162306a36Sopenharmony_ci		    "BG_%d : i=%d cq_id=%d\n", i, req->cq_id);
19262306a36Sopenharmony_ci	req->defq_id = def_hdr_id;
19362306a36Sopenharmony_ci	req->hdr_ring_id = def_hdr_id;
19462306a36Sopenharmony_ci	req->data_ring_id = def_data_id;
19562306a36Sopenharmony_ci	req->do_offload = 1;
19662306a36Sopenharmony_ci	req->dataout_template_pa.lo = ptemplate_address->lo;
19762306a36Sopenharmony_ci	req->dataout_template_pa.hi = ptemplate_address->hi;
19862306a36Sopenharmony_ci	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
19962306a36Sopenharmony_ci	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
20062306a36Sopenharmony_ci	sge->len = cpu_to_le32(nonemb_cmd->size);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (!is_chip_be2_be3r(phba)) {
20362306a36Sopenharmony_ci		req->hdr.version = MBX_CMD_VER1;
20462306a36Sopenharmony_ci		req->tcp_window_size = 0x8000;
20562306a36Sopenharmony_ci		req->tcp_window_scale_count = 2;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
20962306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
21062306a36Sopenharmony_ci	return tag;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/**
21462306a36Sopenharmony_ci * beiscsi_exec_nemb_cmd()- execute non-embedded MBX cmd
21562306a36Sopenharmony_ci * @phba: driver priv structure
21662306a36Sopenharmony_ci * @nonemb_cmd: DMA address of the MBX command to be issued
21762306a36Sopenharmony_ci * @cbfn: callback func on MCC completion
21862306a36Sopenharmony_ci * @resp_buf: buffer to copy the MBX cmd response
21962306a36Sopenharmony_ci * @resp_buf_len: response length to be copied
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci **/
22262306a36Sopenharmony_cistatic int beiscsi_exec_nemb_cmd(struct beiscsi_hba *phba,
22362306a36Sopenharmony_ci				 struct be_dma_mem *nonemb_cmd,
22462306a36Sopenharmony_ci				 void (*cbfn)(struct beiscsi_hba *,
22562306a36Sopenharmony_ci					      unsigned int),
22662306a36Sopenharmony_ci				 void *resp_buf, u32 resp_buf_len)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
22962306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
23062306a36Sopenharmony_ci	struct be_sge *sge;
23162306a36Sopenharmony_ci	unsigned int tag;
23262306a36Sopenharmony_ci	int rc = 0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
23562306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
23662306a36Sopenharmony_ci	if (!wrb) {
23762306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
23862306a36Sopenharmony_ci		return -ENOMEM;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	sge = nonembedded_sgl(wrb);
24262306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
24362306a36Sopenharmony_ci	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
24462306a36Sopenharmony_ci	sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma));
24562306a36Sopenharmony_ci	sge->len = cpu_to_le32(nonemb_cmd->size);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (cbfn) {
24862306a36Sopenharmony_ci		struct be_dma_mem *tag_mem;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
25162306a36Sopenharmony_ci		ctrl->ptag_state[tag].cbfn = cbfn;
25262306a36Sopenharmony_ci		tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		/* store DMA mem to be freed in callback */
25562306a36Sopenharmony_ci		tag_mem->size = nonemb_cmd->size;
25662306a36Sopenharmony_ci		tag_mem->va = nonemb_cmd->va;
25762306a36Sopenharmony_ci		tag_mem->dma = nonemb_cmd->dma;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
26062306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* with cbfn set, its async cmd, don't wait */
26362306a36Sopenharmony_ci	if (cbfn)
26462306a36Sopenharmony_ci		return 0;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	rc = beiscsi_mccq_compl_wait(phba, tag, NULL, nonemb_cmd);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* copy the response, if any */
26962306a36Sopenharmony_ci	if (resp_buf)
27062306a36Sopenharmony_ci		memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
27162306a36Sopenharmony_ci	return rc;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba,
27562306a36Sopenharmony_ci				 struct be_dma_mem *cmd,
27662306a36Sopenharmony_ci				 u8 subsystem, u8 opcode, u32 size)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma,
27962306a36Sopenharmony_ci				     GFP_KERNEL);
28062306a36Sopenharmony_ci	if (!cmd->va) {
28162306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
28262306a36Sopenharmony_ci			    "BG_%d : Failed to allocate memory for if info\n");
28362306a36Sopenharmony_ci		return -ENOMEM;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	cmd->size = size;
28662306a36Sopenharmony_ci	be_cmd_hdr_prepare(cmd->va, subsystem, opcode, size);
28762306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
28862306a36Sopenharmony_ci		    "BG_%d : subsystem %u cmd %u size %u\n",
28962306a36Sopenharmony_ci		    subsystem, opcode, size);
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void beiscsi_free_nemb_cmd(struct beiscsi_hba *phba,
29462306a36Sopenharmony_ci				  struct be_dma_mem *cmd, int rc)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	/*
29762306a36Sopenharmony_ci	 * If FW is busy the DMA buffer is saved with the tag. When the cmd
29862306a36Sopenharmony_ci	 * completes this buffer is freed.
29962306a36Sopenharmony_ci	 */
30062306a36Sopenharmony_ci	if (rc == -EBUSY)
30162306a36Sopenharmony_ci		return;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	dma_free_coherent(&phba->ctrl.pdev->dev, cmd->size, cmd->va, cmd->dma);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void __beiscsi_eq_delay_compl(struct beiscsi_hba *phba, unsigned int tag)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct be_dma_mem *tag_mem;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* status is ignored */
31162306a36Sopenharmony_ci	__beiscsi_mcc_compl_status(phba, tag, NULL, NULL);
31262306a36Sopenharmony_ci	tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
31362306a36Sopenharmony_ci	if (tag_mem->size) {
31462306a36Sopenharmony_ci		dma_free_coherent(&phba->pcidev->dev, tag_mem->size,
31562306a36Sopenharmony_ci				    tag_mem->va, tag_mem->dma);
31662306a36Sopenharmony_ci		tag_mem->size = 0;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciint beiscsi_modify_eq_delay(struct beiscsi_hba *phba,
32162306a36Sopenharmony_ci			    struct be_set_eqd *set_eqd, int num)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct be_cmd_req_modify_eq_delay *req;
32462306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
32562306a36Sopenharmony_ci	int i, rc;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_COMMON,
32862306a36Sopenharmony_ci			OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
32962306a36Sopenharmony_ci	if (rc)
33062306a36Sopenharmony_ci		return rc;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	req = nonemb_cmd.va;
33362306a36Sopenharmony_ci	req->num_eq = cpu_to_le32(num);
33462306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
33562306a36Sopenharmony_ci		req->delay[i].eq_id = cpu_to_le32(set_eqd[i].eq_id);
33662306a36Sopenharmony_ci		req->delay[i].phase = 0;
33762306a36Sopenharmony_ci		req->delay[i].delay_multiplier =
33862306a36Sopenharmony_ci				cpu_to_le32(set_eqd[i].delay_multiplier);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, __beiscsi_eq_delay_compl,
34262306a36Sopenharmony_ci				   NULL, 0);
34362306a36Sopenharmony_ci	if (rc) {
34462306a36Sopenharmony_ci		/*
34562306a36Sopenharmony_ci		 * Only free on failure. Async cmds are handled like -EBUSY
34662306a36Sopenharmony_ci		 * where it's handled for us.
34762306a36Sopenharmony_ci		 */
34862306a36Sopenharmony_ci		beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci	return rc;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/**
35462306a36Sopenharmony_ci * beiscsi_get_initiator_name - read initiator name from flash
35562306a36Sopenharmony_ci * @phba: device priv structure
35662306a36Sopenharmony_ci * @name: buffer pointer
35762306a36Sopenharmony_ci * @cfg: fetch user configured
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_ciint beiscsi_get_initiator_name(struct beiscsi_hba *phba, char *name, bool cfg)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
36362306a36Sopenharmony_ci	struct be_cmd_hba_name resp;
36462306a36Sopenharmony_ci	struct be_cmd_hba_name *req;
36562306a36Sopenharmony_ci	int rc;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI_INI,
36862306a36Sopenharmony_ci			OPCODE_ISCSI_INI_CFG_GET_HBA_NAME, sizeof(resp));
36962306a36Sopenharmony_ci	if (rc)
37062306a36Sopenharmony_ci		return rc;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	req = nonemb_cmd.va;
37362306a36Sopenharmony_ci	if (cfg)
37462306a36Sopenharmony_ci		req->hdr.version = 1;
37562306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL,
37662306a36Sopenharmony_ci				   &resp, sizeof(resp));
37762306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
37862306a36Sopenharmony_ci	if (rc) {
37962306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
38062306a36Sopenharmony_ci			    BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
38162306a36Sopenharmony_ci			    "BS_%d : Initiator Name MBX Failed\n");
38262306a36Sopenharmony_ci		return rc;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	rc = sprintf(name, "%s\n", resp.initiator_name);
38562306a36Sopenharmony_ci	return rc;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ciunsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
39162306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
39262306a36Sopenharmony_ci	struct be_cmd_get_all_if_id_req *req;
39362306a36Sopenharmony_ci	struct be_cmd_get_all_if_id_req *pbe_allid;
39462306a36Sopenharmony_ci	unsigned int tag;
39562306a36Sopenharmony_ci	int status = 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ctrl->mbox_lock))
39862306a36Sopenharmony_ci		return -EINTR;
39962306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
40062306a36Sopenharmony_ci	if (!wrb) {
40162306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
40262306a36Sopenharmony_ci		return -ENOMEM;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	req = embedded_payload(wrb);
40662306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
40762306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
40862306a36Sopenharmony_ci			   OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
40962306a36Sopenharmony_ci			   sizeof(*req));
41062306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
41162306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
41462306a36Sopenharmony_ci	if (status) {
41562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
41662306a36Sopenharmony_ci			    "BG_%d : %s failed: %d\n", __func__, status);
41762306a36Sopenharmony_ci		return -EBUSY;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	pbe_allid = embedded_payload(wrb);
42162306a36Sopenharmony_ci	/* we now support only one interface per function */
42262306a36Sopenharmony_ci	phba->interface_handle = pbe_allid->if_hndl_list[0];
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return status;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	u32 len;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN;
43262306a36Sopenharmony_ci	while (len && !ip[len - 1])
43362306a36Sopenharmony_ci		len--;
43462306a36Sopenharmony_ci	return (len == 0);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int beiscsi_if_mod_gw(struct beiscsi_hba *phba,
43862306a36Sopenharmony_ci			     u32 action, u32 ip_type, u8 *gw)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct be_cmd_set_def_gateway_req *req;
44162306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
44262306a36Sopenharmony_ci	int rt_val;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	rt_val = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
44562306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY,
44662306a36Sopenharmony_ci			sizeof(*req));
44762306a36Sopenharmony_ci	if (rt_val)
44862306a36Sopenharmony_ci		return rt_val;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	req = nonemb_cmd.va;
45162306a36Sopenharmony_ci	req->action = action;
45262306a36Sopenharmony_ci	req->ip_addr.ip_type = ip_type;
45362306a36Sopenharmony_ci	memcpy(req->ip_addr.addr, gw,
45462306a36Sopenharmony_ci	       (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN);
45562306a36Sopenharmony_ci	rt_val = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0);
45662306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rt_val);
45762306a36Sopenharmony_ci	return rt_val;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ciint beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct be_cmd_get_def_gateway_resp gw_resp;
46362306a36Sopenharmony_ci	int rt_val;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	memset(&gw_resp, 0, sizeof(gw_resp));
46662306a36Sopenharmony_ci	rt_val = beiscsi_if_get_gw(phba, ip_type, &gw_resp);
46762306a36Sopenharmony_ci	if (rt_val) {
46862306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
46962306a36Sopenharmony_ci			    "BG_%d : Failed to Get Gateway Addr\n");
47062306a36Sopenharmony_ci		return rt_val;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (!beiscsi_if_zero_ip(gw_resp.ip_addr.addr, ip_type)) {
47462306a36Sopenharmony_ci		rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, ip_type,
47562306a36Sopenharmony_ci					   gw_resp.ip_addr.addr);
47662306a36Sopenharmony_ci		if (rt_val) {
47762306a36Sopenharmony_ci			beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
47862306a36Sopenharmony_ci				    "BG_%d : Failed to clear Gateway Addr Set\n");
47962306a36Sopenharmony_ci			return rt_val;
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_ADD, ip_type, gw);
48462306a36Sopenharmony_ci	if (rt_val)
48562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
48662306a36Sopenharmony_ci			    "BG_%d : Failed to Set Gateway Addr\n");
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return rt_val;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ciint beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type,
49262306a36Sopenharmony_ci		      struct be_cmd_get_def_gateway_resp *resp)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct be_cmd_get_def_gateway_req *req;
49562306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
49662306a36Sopenharmony_ci	int rc;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
49962306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY,
50062306a36Sopenharmony_ci			sizeof(*resp));
50162306a36Sopenharmony_ci	if (rc)
50262306a36Sopenharmony_ci		return rc;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	req = nonemb_cmd.va;
50562306a36Sopenharmony_ci	req->ip_type = ip_type;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, resp,
50862306a36Sopenharmony_ci				   sizeof(*resp));
50962306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
51062306a36Sopenharmony_ci	return rc;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int
51462306a36Sopenharmony_cibeiscsi_if_clr_ip(struct beiscsi_hba *phba,
51562306a36Sopenharmony_ci		  struct be_cmd_get_if_info_resp *if_info)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct be_cmd_set_ip_addr_req *req;
51862306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
51962306a36Sopenharmony_ci	int rc;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
52262306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
52362306a36Sopenharmony_ci			sizeof(*req));
52462306a36Sopenharmony_ci	if (rc)
52562306a36Sopenharmony_ci		return rc;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	req = nonemb_cmd.va;
52862306a36Sopenharmony_ci	req->ip_params.record_entry_count = 1;
52962306a36Sopenharmony_ci	req->ip_params.ip_record.action = IP_ACTION_DEL;
53062306a36Sopenharmony_ci	req->ip_params.ip_record.interface_hndl =
53162306a36Sopenharmony_ci		phba->interface_handle;
53262306a36Sopenharmony_ci	req->ip_params.ip_record.ip_addr.size_of_structure =
53362306a36Sopenharmony_ci		sizeof(struct be_ip_addr_subnet_format);
53462306a36Sopenharmony_ci	req->ip_params.ip_record.ip_addr.ip_type = if_info->ip_addr.ip_type;
53562306a36Sopenharmony_ci	memcpy(req->ip_params.ip_record.ip_addr.addr,
53662306a36Sopenharmony_ci	       if_info->ip_addr.addr,
53762306a36Sopenharmony_ci	       sizeof(if_info->ip_addr.addr));
53862306a36Sopenharmony_ci	memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
53962306a36Sopenharmony_ci	       if_info->ip_addr.subnet_mask,
54062306a36Sopenharmony_ci	       sizeof(if_info->ip_addr.subnet_mask));
54162306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0);
54262306a36Sopenharmony_ci	if (rc < 0 || req->ip_params.ip_record.status) {
54362306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
54462306a36Sopenharmony_ci			    "BG_%d : failed to clear IP: rc %d status %d\n",
54562306a36Sopenharmony_ci			    rc, req->ip_params.ip_record.status);
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
54862306a36Sopenharmony_ci	return rc;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic int
55262306a36Sopenharmony_cibeiscsi_if_set_ip(struct beiscsi_hba *phba, u8 *ip,
55362306a36Sopenharmony_ci		  u8 *subnet, u32 ip_type)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct be_cmd_set_ip_addr_req *req;
55662306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
55762306a36Sopenharmony_ci	uint32_t ip_len;
55862306a36Sopenharmony_ci	int rc;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
56162306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
56262306a36Sopenharmony_ci			sizeof(*req));
56362306a36Sopenharmony_ci	if (rc)
56462306a36Sopenharmony_ci		return rc;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	req = nonemb_cmd.va;
56762306a36Sopenharmony_ci	req->ip_params.record_entry_count = 1;
56862306a36Sopenharmony_ci	req->ip_params.ip_record.action = IP_ACTION_ADD;
56962306a36Sopenharmony_ci	req->ip_params.ip_record.interface_hndl =
57062306a36Sopenharmony_ci		phba->interface_handle;
57162306a36Sopenharmony_ci	req->ip_params.ip_record.ip_addr.size_of_structure =
57262306a36Sopenharmony_ci		sizeof(struct be_ip_addr_subnet_format);
57362306a36Sopenharmony_ci	req->ip_params.ip_record.ip_addr.ip_type = ip_type;
57462306a36Sopenharmony_ci	ip_len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN;
57562306a36Sopenharmony_ci	memcpy(req->ip_params.ip_record.ip_addr.addr, ip, ip_len);
57662306a36Sopenharmony_ci	if (subnet)
57762306a36Sopenharmony_ci		memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
57862306a36Sopenharmony_ci		       subnet, ip_len);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0);
58162306a36Sopenharmony_ci	/**
58262306a36Sopenharmony_ci	 * In some cases, host needs to look into individual record status
58362306a36Sopenharmony_ci	 * even though FW reported success for that IOCTL.
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci	if (rc < 0 || req->ip_params.ip_record.status) {
58662306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
58762306a36Sopenharmony_ci			    "BG_%d : failed to set IP: rc %d status %d\n",
58862306a36Sopenharmony_ci			    rc, req->ip_params.ip_record.status);
58962306a36Sopenharmony_ci		if (req->ip_params.ip_record.status)
59062306a36Sopenharmony_ci			rc = -EINVAL;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
59362306a36Sopenharmony_ci	return rc;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciint beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type,
59762306a36Sopenharmony_ci			 u8 *ip, u8 *subnet)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct be_cmd_get_if_info_resp *if_info;
60062306a36Sopenharmony_ci	struct be_cmd_rel_dhcp_req *reldhcp;
60162306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
60262306a36Sopenharmony_ci	int rc;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	rc = beiscsi_if_get_info(phba, ip_type, &if_info);
60562306a36Sopenharmony_ci	if (rc)
60662306a36Sopenharmony_ci		return rc;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (if_info->dhcp_state) {
60962306a36Sopenharmony_ci		rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd,
61062306a36Sopenharmony_ci				CMD_SUBSYSTEM_ISCSI,
61162306a36Sopenharmony_ci				OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR,
61262306a36Sopenharmony_ci				sizeof(*reldhcp));
61362306a36Sopenharmony_ci		if (rc)
61462306a36Sopenharmony_ci			goto exit;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		reldhcp = nonemb_cmd.va;
61762306a36Sopenharmony_ci		reldhcp->interface_hndl = phba->interface_handle;
61862306a36Sopenharmony_ci		reldhcp->ip_type = ip_type;
61962306a36Sopenharmony_ci		rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0);
62062306a36Sopenharmony_ci		beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
62162306a36Sopenharmony_ci		if (rc < 0) {
62262306a36Sopenharmony_ci			beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
62362306a36Sopenharmony_ci				    "BG_%d : failed to release existing DHCP: %d\n",
62462306a36Sopenharmony_ci				    rc);
62562306a36Sopenharmony_ci			goto exit;
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/* first delete any IP set */
63062306a36Sopenharmony_ci	if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) {
63162306a36Sopenharmony_ci		rc = beiscsi_if_clr_ip(phba, if_info);
63262306a36Sopenharmony_ci		if (rc)
63362306a36Sopenharmony_ci			goto exit;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* if ip == NULL then this is called just to release DHCP IP */
63762306a36Sopenharmony_ci	if (ip)
63862306a36Sopenharmony_ci		rc = beiscsi_if_set_ip(phba, ip, subnet, ip_type);
63962306a36Sopenharmony_ciexit:
64062306a36Sopenharmony_ci	kfree(if_info);
64162306a36Sopenharmony_ci	return rc;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciint beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct be_cmd_get_def_gateway_resp gw_resp;
64762306a36Sopenharmony_ci	struct be_cmd_get_if_info_resp *if_info;
64862306a36Sopenharmony_ci	struct be_cmd_set_dhcp_req *dhcpreq;
64962306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
65062306a36Sopenharmony_ci	u8 *gw;
65162306a36Sopenharmony_ci	int rc;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	rc = beiscsi_if_get_info(phba, ip_type, &if_info);
65462306a36Sopenharmony_ci	if (rc)
65562306a36Sopenharmony_ci		return rc;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (if_info->dhcp_state) {
65862306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
65962306a36Sopenharmony_ci				"BG_%d : DHCP Already Enabled\n");
66062306a36Sopenharmony_ci		goto exit;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* first delete any IP set */
66462306a36Sopenharmony_ci	if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) {
66562306a36Sopenharmony_ci		rc = beiscsi_if_clr_ip(phba, if_info);
66662306a36Sopenharmony_ci		if (rc)
66762306a36Sopenharmony_ci			goto exit;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* delete gateway settings if mode change is to DHCP */
67162306a36Sopenharmony_ci	memset(&gw_resp, 0, sizeof(gw_resp));
67262306a36Sopenharmony_ci	/* use ip_type provided in if_info */
67362306a36Sopenharmony_ci	rc = beiscsi_if_get_gw(phba, if_info->ip_addr.ip_type, &gw_resp);
67462306a36Sopenharmony_ci	if (rc) {
67562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
67662306a36Sopenharmony_ci			    "BG_%d : Failed to Get Gateway Addr\n");
67762306a36Sopenharmony_ci		goto exit;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci	gw = (u8 *)&gw_resp.ip_addr.addr;
68062306a36Sopenharmony_ci	if (!beiscsi_if_zero_ip(gw, if_info->ip_addr.ip_type)) {
68162306a36Sopenharmony_ci		rc = beiscsi_if_mod_gw(phba, IP_ACTION_DEL,
68262306a36Sopenharmony_ci				       if_info->ip_addr.ip_type, gw);
68362306a36Sopenharmony_ci		if (rc) {
68462306a36Sopenharmony_ci			beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
68562306a36Sopenharmony_ci				    "BG_%d : Failed to clear Gateway Addr Set\n");
68662306a36Sopenharmony_ci			goto exit;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
69162306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR,
69262306a36Sopenharmony_ci			sizeof(*dhcpreq));
69362306a36Sopenharmony_ci	if (rc)
69462306a36Sopenharmony_ci		goto exit;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	dhcpreq = nonemb_cmd.va;
69762306a36Sopenharmony_ci	dhcpreq->flags = 1; /* 1 - blocking; 0 - non-blocking */
69862306a36Sopenharmony_ci	dhcpreq->retry_count = 1;
69962306a36Sopenharmony_ci	dhcpreq->interface_hndl = phba->interface_handle;
70062306a36Sopenharmony_ci	dhcpreq->ip_type = ip_type;
70162306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0);
70262306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
70362306a36Sopenharmony_ciexit:
70462306a36Sopenharmony_ci	kfree(if_info);
70562306a36Sopenharmony_ci	return rc;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci/**
70962306a36Sopenharmony_ci * beiscsi_if_set_vlan()- Issue and wait for CMD completion
71062306a36Sopenharmony_ci * @phba: device private structure instance
71162306a36Sopenharmony_ci * @vlan_tag: VLAN tag
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * Issue the MBX Cmd and wait for the completion of the
71462306a36Sopenharmony_ci * command.
71562306a36Sopenharmony_ci *
71662306a36Sopenharmony_ci * returns
71762306a36Sopenharmony_ci *	Success: 0
71862306a36Sopenharmony_ci *	Failure: Non-Xero Value
71962306a36Sopenharmony_ci **/
72062306a36Sopenharmony_ciint beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	int rc;
72362306a36Sopenharmony_ci	unsigned int tag;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	tag = be_cmd_set_vlan(phba, vlan_tag);
72662306a36Sopenharmony_ci	if (!tag) {
72762306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
72862306a36Sopenharmony_ci			    (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
72962306a36Sopenharmony_ci			    "BG_%d : VLAN Setting Failed\n");
73062306a36Sopenharmony_ci		return -EBUSY;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
73462306a36Sopenharmony_ci	if (rc) {
73562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
73662306a36Sopenharmony_ci			    (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
73762306a36Sopenharmony_ci			    "BS_%d : VLAN MBX Cmd Failed\n");
73862306a36Sopenharmony_ci		return rc;
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	return rc;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ciint beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type,
74562306a36Sopenharmony_ci			struct be_cmd_get_if_info_resp **if_info)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct be_cmd_get_if_info_req *req;
74862306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
74962306a36Sopenharmony_ci	uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp);
75062306a36Sopenharmony_ci	int rc;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	rc = beiscsi_if_get_handle(phba);
75362306a36Sopenharmony_ci	if (rc)
75462306a36Sopenharmony_ci		return rc;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	do {
75762306a36Sopenharmony_ci		rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd,
75862306a36Sopenharmony_ci				CMD_SUBSYSTEM_ISCSI,
75962306a36Sopenharmony_ci				OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO,
76062306a36Sopenharmony_ci				ioctl_size);
76162306a36Sopenharmony_ci		if (rc)
76262306a36Sopenharmony_ci			return rc;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		req = nonemb_cmd.va;
76562306a36Sopenharmony_ci		req->interface_hndl = phba->interface_handle;
76662306a36Sopenharmony_ci		req->ip_type = ip_type;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		/* Allocate memory for if_info */
76962306a36Sopenharmony_ci		*if_info = kzalloc(ioctl_size, GFP_KERNEL);
77062306a36Sopenharmony_ci		if (!*if_info) {
77162306a36Sopenharmony_ci			beiscsi_log(phba, KERN_ERR,
77262306a36Sopenharmony_ci				    BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
77362306a36Sopenharmony_ci				    "BG_%d : Memory Allocation Failure\n");
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci				beiscsi_free_nemb_cmd(phba, &nonemb_cmd,
77662306a36Sopenharmony_ci						      -ENOMEM);
77762306a36Sopenharmony_ci				return -ENOMEM;
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		rc =  beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, *if_info,
78162306a36Sopenharmony_ci					    ioctl_size);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		/* Check if the error is because of Insufficent_Buffer */
78462306a36Sopenharmony_ci		if (rc == -EAGAIN) {
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci			/* Get the new memory size */
78762306a36Sopenharmony_ci			ioctl_size = ((struct be_cmd_resp_hdr *)
78862306a36Sopenharmony_ci				      nonemb_cmd.va)->actual_resp_len;
78962306a36Sopenharmony_ci			ioctl_size += sizeof(struct be_cmd_req_hdr);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci			beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
79262306a36Sopenharmony_ci			/* Free the virtual memory */
79362306a36Sopenharmony_ci			kfree(*if_info);
79462306a36Sopenharmony_ci		} else {
79562306a36Sopenharmony_ci			beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
79662306a36Sopenharmony_ci			break;
79762306a36Sopenharmony_ci		}
79862306a36Sopenharmony_ci	} while (true);
79962306a36Sopenharmony_ci	return rc;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ciint mgmt_get_nic_conf(struct beiscsi_hba *phba,
80362306a36Sopenharmony_ci		      struct be_cmd_get_nic_conf_resp *nic)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
80662306a36Sopenharmony_ci	int rc;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI,
80962306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
81062306a36Sopenharmony_ci			sizeof(*nic));
81162306a36Sopenharmony_ci	if (rc)
81262306a36Sopenharmony_ci		return rc;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, nic, sizeof(*nic));
81562306a36Sopenharmony_ci	beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc);
81662306a36Sopenharmony_ci	return rc;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void beiscsi_boot_process_compl(struct beiscsi_hba *phba,
82062306a36Sopenharmony_ci				       unsigned int tag)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct be_cmd_get_boot_target_resp *boot_resp;
82362306a36Sopenharmony_ci	struct be_cmd_resp_logout_fw_sess *logo_resp;
82462306a36Sopenharmony_ci	struct be_cmd_get_session_resp *sess_resp;
82562306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
82662306a36Sopenharmony_ci	struct boot_struct *bs;
82762306a36Sopenharmony_ci	int boot_work, status;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (!test_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) {
83062306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
83162306a36Sopenharmony_ci			      "BG_%d : %s no boot work %lx\n",
83262306a36Sopenharmony_ci			      __func__, phba->state);
83362306a36Sopenharmony_ci		return;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (phba->boot_struct.tag != tag) {
83762306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
83862306a36Sopenharmony_ci			      "BG_%d : %s tag mismatch %d:%d\n",
83962306a36Sopenharmony_ci			      __func__, tag, phba->boot_struct.tag);
84062306a36Sopenharmony_ci		return;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	bs = &phba->boot_struct;
84362306a36Sopenharmony_ci	boot_work = 1;
84462306a36Sopenharmony_ci	status = 0;
84562306a36Sopenharmony_ci	switch (bs->action) {
84662306a36Sopenharmony_ci	case BEISCSI_BOOT_REOPEN_SESS:
84762306a36Sopenharmony_ci		status = __beiscsi_mcc_compl_status(phba, tag, NULL, NULL);
84862306a36Sopenharmony_ci		if (!status)
84962306a36Sopenharmony_ci			bs->action = BEISCSI_BOOT_GET_SHANDLE;
85062306a36Sopenharmony_ci		else
85162306a36Sopenharmony_ci			bs->retry--;
85262306a36Sopenharmony_ci		break;
85362306a36Sopenharmony_ci	case BEISCSI_BOOT_GET_SHANDLE:
85462306a36Sopenharmony_ci		status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL);
85562306a36Sopenharmony_ci		if (!status) {
85662306a36Sopenharmony_ci			boot_resp = embedded_payload(wrb);
85762306a36Sopenharmony_ci			bs->s_handle = boot_resp->boot_session_handle;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci		if (bs->s_handle == BE_BOOT_INVALID_SHANDLE) {
86062306a36Sopenharmony_ci			bs->action = BEISCSI_BOOT_REOPEN_SESS;
86162306a36Sopenharmony_ci			bs->retry--;
86262306a36Sopenharmony_ci		} else {
86362306a36Sopenharmony_ci			bs->action = BEISCSI_BOOT_GET_SINFO;
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci		break;
86662306a36Sopenharmony_ci	case BEISCSI_BOOT_GET_SINFO:
86762306a36Sopenharmony_ci		status = __beiscsi_mcc_compl_status(phba, tag, NULL,
86862306a36Sopenharmony_ci						    &bs->nonemb_cmd);
86962306a36Sopenharmony_ci		if (!status) {
87062306a36Sopenharmony_ci			sess_resp = bs->nonemb_cmd.va;
87162306a36Sopenharmony_ci			memcpy(&bs->boot_sess, &sess_resp->session_info,
87262306a36Sopenharmony_ci			       sizeof(struct mgmt_session_info));
87362306a36Sopenharmony_ci			bs->action = BEISCSI_BOOT_LOGOUT_SESS;
87462306a36Sopenharmony_ci		} else {
87562306a36Sopenharmony_ci			__beiscsi_log(phba, KERN_ERR,
87662306a36Sopenharmony_ci				      "BG_%d : get boot session info error : 0x%x\n",
87762306a36Sopenharmony_ci				      status);
87862306a36Sopenharmony_ci			boot_work = 0;
87962306a36Sopenharmony_ci		}
88062306a36Sopenharmony_ci		dma_free_coherent(&phba->ctrl.pdev->dev, bs->nonemb_cmd.size,
88162306a36Sopenharmony_ci				    bs->nonemb_cmd.va, bs->nonemb_cmd.dma);
88262306a36Sopenharmony_ci		bs->nonemb_cmd.va = NULL;
88362306a36Sopenharmony_ci		break;
88462306a36Sopenharmony_ci	case BEISCSI_BOOT_LOGOUT_SESS:
88562306a36Sopenharmony_ci		status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL);
88662306a36Sopenharmony_ci		if (!status) {
88762306a36Sopenharmony_ci			logo_resp = embedded_payload(wrb);
88862306a36Sopenharmony_ci			if (logo_resp->session_status != BE_SESS_STATUS_CLOSE) {
88962306a36Sopenharmony_ci				__beiscsi_log(phba, KERN_ERR,
89062306a36Sopenharmony_ci					      "BG_%d : FW boot session logout error : 0x%x\n",
89162306a36Sopenharmony_ci					      logo_resp->session_status);
89262306a36Sopenharmony_ci			}
89362306a36Sopenharmony_ci		}
89462306a36Sopenharmony_ci		/* continue to create boot_kset even if logout failed? */
89562306a36Sopenharmony_ci		bs->action = BEISCSI_BOOT_CREATE_KSET;
89662306a36Sopenharmony_ci		break;
89762306a36Sopenharmony_ci	default:
89862306a36Sopenharmony_ci		break;
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* clear the tag so no other completion matches this tag */
90262306a36Sopenharmony_ci	bs->tag = 0;
90362306a36Sopenharmony_ci	if (!bs->retry) {
90462306a36Sopenharmony_ci		boot_work = 0;
90562306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
90662306a36Sopenharmony_ci			      "BG_%d : failed to setup boot target: status %d action %d\n",
90762306a36Sopenharmony_ci			      status, bs->action);
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci	if (!boot_work) {
91062306a36Sopenharmony_ci		/* wait for next event to start boot_work */
91162306a36Sopenharmony_ci		clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state);
91262306a36Sopenharmony_ci		return;
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci	schedule_work(&phba->boot_work);
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/**
91862306a36Sopenharmony_ci * beiscsi_boot_logout_sess()- Logout from boot FW session
91962306a36Sopenharmony_ci * @phba: Device priv structure instance
92062306a36Sopenharmony_ci *
92162306a36Sopenharmony_ci * return
92262306a36Sopenharmony_ci *	the TAG used for MBOX Command
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci */
92562306a36Sopenharmony_ciunsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
92862306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
92962306a36Sopenharmony_ci	struct be_cmd_req_logout_fw_sess *req;
93062306a36Sopenharmony_ci	unsigned int tag;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
93362306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
93462306a36Sopenharmony_ci	if (!wrb) {
93562306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
93662306a36Sopenharmony_ci		return 0;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	req = embedded_payload(wrb);
94062306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
94162306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
94262306a36Sopenharmony_ci			   OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET,
94362306a36Sopenharmony_ci			   sizeof(struct be_cmd_req_logout_fw_sess));
94462306a36Sopenharmony_ci	/* Use the session handle copied into boot_sess */
94562306a36Sopenharmony_ci	req->session_handle = phba->boot_struct.boot_sess.session_handle;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	phba->boot_struct.tag = tag;
94862306a36Sopenharmony_ci	set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
94962306a36Sopenharmony_ci	ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
95262306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return tag;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci/**
95762306a36Sopenharmony_ci * beiscsi_boot_reopen_sess()- Reopen boot session
95862306a36Sopenharmony_ci * @phba: Device priv structure instance
95962306a36Sopenharmony_ci *
96062306a36Sopenharmony_ci * return
96162306a36Sopenharmony_ci *	the TAG used for MBOX Command
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci **/
96462306a36Sopenharmony_ciunsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
96762306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
96862306a36Sopenharmony_ci	struct be_cmd_reopen_session_req *req;
96962306a36Sopenharmony_ci	unsigned int tag;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
97262306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
97362306a36Sopenharmony_ci	if (!wrb) {
97462306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
97562306a36Sopenharmony_ci		return 0;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	req = embedded_payload(wrb);
97962306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
98062306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
98162306a36Sopenharmony_ci			   OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS,
98262306a36Sopenharmony_ci			   sizeof(struct be_cmd_reopen_session_resp));
98362306a36Sopenharmony_ci	req->reopen_type = BE_REOPEN_BOOT_SESSIONS;
98462306a36Sopenharmony_ci	req->session_handle = BE_BOOT_INVALID_SHANDLE;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	phba->boot_struct.tag = tag;
98762306a36Sopenharmony_ci	set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
98862306a36Sopenharmony_ci	ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
99162306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
99262306a36Sopenharmony_ci	return tag;
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci/**
99762306a36Sopenharmony_ci * beiscsi_boot_get_sinfo()- Get boot session info
99862306a36Sopenharmony_ci * @phba: device priv structure instance
99962306a36Sopenharmony_ci *
100062306a36Sopenharmony_ci * Fetches the boot_struct.s_handle info from FW.
100162306a36Sopenharmony_ci * return
100262306a36Sopenharmony_ci *	the TAG used for MBOX Command
100362306a36Sopenharmony_ci *
100462306a36Sopenharmony_ci **/
100562306a36Sopenharmony_ciunsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
100862306a36Sopenharmony_ci	struct be_cmd_get_session_req *req;
100962306a36Sopenharmony_ci	struct be_dma_mem *nonemb_cmd;
101062306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
101162306a36Sopenharmony_ci	struct be_sge *sge;
101262306a36Sopenharmony_ci	unsigned int tag;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
101562306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
101662306a36Sopenharmony_ci	if (!wrb) {
101762306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
101862306a36Sopenharmony_ci		return 0;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	nonemb_cmd = &phba->boot_struct.nonemb_cmd;
102262306a36Sopenharmony_ci	nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp);
102362306a36Sopenharmony_ci	nonemb_cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
102462306a36Sopenharmony_ci					      nonemb_cmd->size,
102562306a36Sopenharmony_ci					      &nonemb_cmd->dma,
102662306a36Sopenharmony_ci					      GFP_KERNEL);
102762306a36Sopenharmony_ci	if (!nonemb_cmd->va) {
102862306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
102962306a36Sopenharmony_ci		return 0;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	req = nonemb_cmd->va;
103362306a36Sopenharmony_ci	memset(req, 0, sizeof(*req));
103462306a36Sopenharmony_ci	sge = nonembedded_sgl(wrb);
103562306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
103662306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
103762306a36Sopenharmony_ci			   OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
103862306a36Sopenharmony_ci			   sizeof(struct be_cmd_get_session_resp));
103962306a36Sopenharmony_ci	req->session_handle = phba->boot_struct.s_handle;
104062306a36Sopenharmony_ci	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
104162306a36Sopenharmony_ci	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
104262306a36Sopenharmony_ci	sge->len = cpu_to_le32(nonemb_cmd->size);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	phba->boot_struct.tag = tag;
104562306a36Sopenharmony_ci	set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
104662306a36Sopenharmony_ci	ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
104962306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
105062306a36Sopenharmony_ci	return tag;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ciunsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
105662306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
105762306a36Sopenharmony_ci	struct be_cmd_get_boot_target_req *req;
105862306a36Sopenharmony_ci	unsigned int tag;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
106162306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
106262306a36Sopenharmony_ci	if (!wrb) {
106362306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
106462306a36Sopenharmony_ci		return 0;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	req = embedded_payload(wrb);
106862306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
106962306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
107062306a36Sopenharmony_ci			   OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
107162306a36Sopenharmony_ci			   sizeof(struct be_cmd_get_boot_target_resp));
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (async) {
107462306a36Sopenharmony_ci		phba->boot_struct.tag = tag;
107562306a36Sopenharmony_ci		set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
107662306a36Sopenharmony_ci		ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
108062306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
108162306a36Sopenharmony_ci	return tag;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci/**
108562306a36Sopenharmony_ci * beiscsi_boot_get_shandle()- Get boot session handle
108662306a36Sopenharmony_ci * @phba: device priv structure instance
108762306a36Sopenharmony_ci * @s_handle: session handle returned for boot session.
108862306a36Sopenharmony_ci *
108962306a36Sopenharmony_ci * return
109062306a36Sopenharmony_ci *	Success: 1
109162306a36Sopenharmony_ci *	Failure: negative
109262306a36Sopenharmony_ci *
109362306a36Sopenharmony_ci **/
109462306a36Sopenharmony_ciint beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct be_cmd_get_boot_target_resp *boot_resp;
109762306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
109862306a36Sopenharmony_ci	unsigned int tag;
109962306a36Sopenharmony_ci	int rc;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	*s_handle = BE_BOOT_INVALID_SHANDLE;
110262306a36Sopenharmony_ci	/* get configured boot session count and handle */
110362306a36Sopenharmony_ci	tag = __beiscsi_boot_get_shandle(phba, 0);
110462306a36Sopenharmony_ci	if (!tag) {
110562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
110662306a36Sopenharmony_ci			    BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
110762306a36Sopenharmony_ci			    "BG_%d : Getting Boot Target Info Failed\n");
110862306a36Sopenharmony_ci		return -EAGAIN;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
111262306a36Sopenharmony_ci	if (rc) {
111362306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
111462306a36Sopenharmony_ci			    BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
111562306a36Sopenharmony_ci			    "BG_%d : MBX CMD get_boot_target Failed\n");
111662306a36Sopenharmony_ci		return -EBUSY;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	boot_resp = embedded_payload(wrb);
112062306a36Sopenharmony_ci	/* check if there are any boot targets configured */
112162306a36Sopenharmony_ci	if (!boot_resp->boot_session_count) {
112262306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_INFO,
112362306a36Sopenharmony_ci			      "BG_%d : No boot targets configured\n");
112462306a36Sopenharmony_ci		return -ENXIO;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* only if FW has logged in to the boot target, s_handle is valid */
112862306a36Sopenharmony_ci	*s_handle = boot_resp->boot_session_handle;
112962306a36Sopenharmony_ci	return 1;
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci/**
113362306a36Sopenharmony_ci * beiscsi_drvr_ver_disp()- Display the driver Name and Version
113462306a36Sopenharmony_ci * @dev: ptr to device not used.
113562306a36Sopenharmony_ci * @attr: device attribute, not used.
113662306a36Sopenharmony_ci * @buf: contains formatted text driver name and version
113762306a36Sopenharmony_ci *
113862306a36Sopenharmony_ci * return
113962306a36Sopenharmony_ci * size of the formatted string
114062306a36Sopenharmony_ci **/
114162306a36Sopenharmony_cissize_t
114262306a36Sopenharmony_cibeiscsi_drvr_ver_disp(struct device *dev, struct device_attribute *attr,
114362306a36Sopenharmony_ci		       char *buf)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, BE_NAME "\n");
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci/**
114962306a36Sopenharmony_ci * beiscsi_fw_ver_disp()- Display Firmware Version
115062306a36Sopenharmony_ci * @dev: ptr to device not used.
115162306a36Sopenharmony_ci * @attr: device attribute, not used.
115262306a36Sopenharmony_ci * @buf: contains formatted text Firmware version
115362306a36Sopenharmony_ci *
115462306a36Sopenharmony_ci * return
115562306a36Sopenharmony_ci * size of the formatted string
115662306a36Sopenharmony_ci **/
115762306a36Sopenharmony_cissize_t
115862306a36Sopenharmony_cibeiscsi_fw_ver_disp(struct device *dev, struct device_attribute *attr,
115962306a36Sopenharmony_ci		     char *buf)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
116262306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", phba->fw_ver_str);
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci/**
116862306a36Sopenharmony_ci * beiscsi_active_session_disp()- Display Sessions Active
116962306a36Sopenharmony_ci * @dev: ptr to device not used.
117062306a36Sopenharmony_ci * @attr: device attribute, not used.
117162306a36Sopenharmony_ci * @buf: contains formatted text Session Count
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * return
117462306a36Sopenharmony_ci * size of the formatted string
117562306a36Sopenharmony_ci **/
117662306a36Sopenharmony_cissize_t
117762306a36Sopenharmony_cibeiscsi_active_session_disp(struct device *dev, struct device_attribute *attr,
117862306a36Sopenharmony_ci			 char *buf)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
118162306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
118262306a36Sopenharmony_ci	uint16_t avlbl_cids = 0, ulp_num, len = 0, total_cids = 0;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
118562306a36Sopenharmony_ci		if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) {
118662306a36Sopenharmony_ci			avlbl_cids = BEISCSI_ULP_AVLBL_CID(phba, ulp_num);
118762306a36Sopenharmony_ci			total_cids = BEISCSI_GET_CID_COUNT(phba, ulp_num);
118862306a36Sopenharmony_ci			len += scnprintf(buf+len, PAGE_SIZE - len,
118962306a36Sopenharmony_ci					 "ULP%d : %d\n", ulp_num,
119062306a36Sopenharmony_ci					 (total_cids - avlbl_cids));
119162306a36Sopenharmony_ci		} else
119262306a36Sopenharmony_ci			len += scnprintf(buf+len, PAGE_SIZE - len,
119362306a36Sopenharmony_ci					 "ULP%d : %d\n", ulp_num, 0);
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return len;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci/**
120062306a36Sopenharmony_ci * beiscsi_free_session_disp()- Display Avaliable Session
120162306a36Sopenharmony_ci * @dev: ptr to device not used.
120262306a36Sopenharmony_ci * @attr: device attribute, not used.
120362306a36Sopenharmony_ci * @buf: contains formatted text Session Count
120462306a36Sopenharmony_ci *
120562306a36Sopenharmony_ci * return
120662306a36Sopenharmony_ci * size of the formatted string
120762306a36Sopenharmony_ci **/
120862306a36Sopenharmony_cissize_t
120962306a36Sopenharmony_cibeiscsi_free_session_disp(struct device *dev, struct device_attribute *attr,
121062306a36Sopenharmony_ci		       char *buf)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
121362306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
121462306a36Sopenharmony_ci	uint16_t ulp_num, len = 0;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
121762306a36Sopenharmony_ci		if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported))
121862306a36Sopenharmony_ci			len += scnprintf(buf+len, PAGE_SIZE - len,
121962306a36Sopenharmony_ci					 "ULP%d : %d\n", ulp_num,
122062306a36Sopenharmony_ci					 BEISCSI_ULP_AVLBL_CID(phba, ulp_num));
122162306a36Sopenharmony_ci		else
122262306a36Sopenharmony_ci			len += scnprintf(buf+len, PAGE_SIZE - len,
122362306a36Sopenharmony_ci					 "ULP%d : %d\n", ulp_num, 0);
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return len;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci/**
123062306a36Sopenharmony_ci * beiscsi_adap_family_disp()- Display adapter family.
123162306a36Sopenharmony_ci * @dev: ptr to device to get priv structure
123262306a36Sopenharmony_ci * @attr: device attribute, not used.
123362306a36Sopenharmony_ci * @buf: contains formatted text driver name and version
123462306a36Sopenharmony_ci *
123562306a36Sopenharmony_ci * return
123662306a36Sopenharmony_ci * size of the formatted string
123762306a36Sopenharmony_ci **/
123862306a36Sopenharmony_cissize_t
123962306a36Sopenharmony_cibeiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
124062306a36Sopenharmony_ci			  char *buf)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	uint16_t dev_id = 0;
124362306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
124462306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	dev_id = phba->pcidev->device;
124762306a36Sopenharmony_ci	switch (dev_id) {
124862306a36Sopenharmony_ci	case BE_DEVICE_ID1:
124962306a36Sopenharmony_ci	case OC_DEVICE_ID1:
125062306a36Sopenharmony_ci	case OC_DEVICE_ID2:
125162306a36Sopenharmony_ci		return snprintf(buf, PAGE_SIZE,
125262306a36Sopenharmony_ci				"Obsolete/Unsupported BE2 Adapter Family\n");
125362306a36Sopenharmony_ci	case BE_DEVICE_ID2:
125462306a36Sopenharmony_ci	case OC_DEVICE_ID3:
125562306a36Sopenharmony_ci		return snprintf(buf, PAGE_SIZE, "BE3-R Adapter Family\n");
125662306a36Sopenharmony_ci	case OC_SKH_ID1:
125762306a36Sopenharmony_ci		return snprintf(buf, PAGE_SIZE, "Skyhawk-R Adapter Family\n");
125862306a36Sopenharmony_ci	default:
125962306a36Sopenharmony_ci		return snprintf(buf, PAGE_SIZE,
126062306a36Sopenharmony_ci				"Unknown Adapter Family: 0x%x\n", dev_id);
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci/**
126562306a36Sopenharmony_ci * beiscsi_phys_port_disp()- Display Physical Port Identifier
126662306a36Sopenharmony_ci * @dev: ptr to device not used.
126762306a36Sopenharmony_ci * @attr: device attribute, not used.
126862306a36Sopenharmony_ci * @buf: contains formatted text port identifier
126962306a36Sopenharmony_ci *
127062306a36Sopenharmony_ci * return
127162306a36Sopenharmony_ci * size of the formatted string
127262306a36Sopenharmony_ci **/
127362306a36Sopenharmony_cissize_t
127462306a36Sopenharmony_cibeiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr,
127562306a36Sopenharmony_ci			 char *buf)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
127862306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "Port Identifier : %u\n",
128162306a36Sopenharmony_ci			phba->fw_config.phys_port);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_civoid beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
128562306a36Sopenharmony_ci			     struct wrb_handle *pwrb_handle,
128662306a36Sopenharmony_ci			     struct be_mem_descriptor *mem_descr,
128762306a36Sopenharmony_ci			     struct hwi_wrb_context *pwrb_context)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
129262306a36Sopenharmony_ci		      max_send_data_segment_length, pwrb,
129362306a36Sopenharmony_ci		      params->dw[offsetof(struct amap_beiscsi_offload_params,
129462306a36Sopenharmony_ci		      max_send_data_segment_length) / 32]);
129562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb,
129662306a36Sopenharmony_ci		      BE_TGT_CTX_UPDT_CMD);
129762306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
129862306a36Sopenharmony_ci		      first_burst_length,
129962306a36Sopenharmony_ci		      pwrb,
130062306a36Sopenharmony_ci		      params->dw[offsetof(struct amap_beiscsi_offload_params,
130162306a36Sopenharmony_ci		      first_burst_length) / 32]);
130262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb,
130362306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
130462306a36Sopenharmony_ci		      erl) / 32] & OFFLD_PARAMS_ERL));
130562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb,
130662306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
130762306a36Sopenharmony_ci		       dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
130862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb,
130962306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
131062306a36Sopenharmony_ci		      hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
131162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb,
131262306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
131362306a36Sopenharmony_ci		      ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
131462306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb,
131562306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
131662306a36Sopenharmony_ci		      imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
131762306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn,
131862306a36Sopenharmony_ci		      pwrb,
131962306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
132062306a36Sopenharmony_ci		      exp_statsn) / 32] + 1));
132162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx,
132262306a36Sopenharmony_ci		      pwrb, pwrb_handle->wrb_index);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
132562306a36Sopenharmony_ci		      max_burst_length, pwrb, params->dw[offsetof
132662306a36Sopenharmony_ci		      (struct amap_beiscsi_offload_params,
132762306a36Sopenharmony_ci		      max_burst_length) / 32]);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
133062306a36Sopenharmony_ci		      pwrb, pwrb_handle->wrb_index);
133162306a36Sopenharmony_ci	if (pwrb_context->plast_wrb)
133262306a36Sopenharmony_ci		AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
133362306a36Sopenharmony_ci			      ptr2nextwrb,
133462306a36Sopenharmony_ci			      pwrb_context->plast_wrb,
133562306a36Sopenharmony_ci			      pwrb_handle->wrb_index);
133662306a36Sopenharmony_ci	pwrb_context->plast_wrb = pwrb;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
133962306a36Sopenharmony_ci		      session_state, pwrb, 0);
134062306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
134162306a36Sopenharmony_ci		      pwrb, 1);
134262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq,
134362306a36Sopenharmony_ci		      pwrb, 0);
134462306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb,
134562306a36Sopenharmony_ci		      0);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	mem_descr += ISCSI_MEM_GLOBAL_HEADER;
134862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
134962306a36Sopenharmony_ci		      pad_buffer_addr_hi, pwrb,
135062306a36Sopenharmony_ci		      mem_descr->mem_array[0].bus_address.u.a32.address_hi);
135162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
135262306a36Sopenharmony_ci		      pad_buffer_addr_lo, pwrb,
135362306a36Sopenharmony_ci		      mem_descr->mem_array[0].bus_address.u.a32.address_lo);
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_civoid beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
135762306a36Sopenharmony_ci			     struct wrb_handle *pwrb_handle,
135862306a36Sopenharmony_ci			     struct hwi_wrb_context *pwrb_context)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
136362306a36Sopenharmony_ci		      max_burst_length, pwrb, params->dw[offsetof
136462306a36Sopenharmony_ci		      (struct amap_beiscsi_offload_params,
136562306a36Sopenharmony_ci		      max_burst_length) / 32]);
136662306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
136762306a36Sopenharmony_ci		      type, pwrb,
136862306a36Sopenharmony_ci		      BE_TGT_CTX_UPDT_CMD);
136962306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
137062306a36Sopenharmony_ci		      ptr2nextwrb,
137162306a36Sopenharmony_ci		      pwrb, pwrb_handle->wrb_index);
137262306a36Sopenharmony_ci	if (pwrb_context->plast_wrb)
137362306a36Sopenharmony_ci		AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
137462306a36Sopenharmony_ci			      ptr2nextwrb,
137562306a36Sopenharmony_ci			      pwrb_context->plast_wrb,
137662306a36Sopenharmony_ci			      pwrb_handle->wrb_index);
137762306a36Sopenharmony_ci	pwrb_context->plast_wrb = pwrb;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx,
138062306a36Sopenharmony_ci		      pwrb, pwrb_handle->wrb_index);
138162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
138262306a36Sopenharmony_ci		      max_send_data_segment_length, pwrb,
138362306a36Sopenharmony_ci		      params->dw[offsetof(struct amap_beiscsi_offload_params,
138462306a36Sopenharmony_ci		      max_send_data_segment_length) / 32]);
138562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
138662306a36Sopenharmony_ci		      first_burst_length, pwrb,
138762306a36Sopenharmony_ci		      params->dw[offsetof(struct amap_beiscsi_offload_params,
138862306a36Sopenharmony_ci		      first_burst_length) / 32]);
138962306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
139062306a36Sopenharmony_ci		      max_recv_dataseg_len, pwrb,
139162306a36Sopenharmony_ci		      params->dw[offsetof(struct amap_beiscsi_offload_params,
139262306a36Sopenharmony_ci		      max_recv_data_segment_length) / 32]);
139362306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
139462306a36Sopenharmony_ci		      max_cxns, pwrb, BEISCSI_MAX_CXNS);
139562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, erl, pwrb,
139662306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
139762306a36Sopenharmony_ci		      erl) / 32] & OFFLD_PARAMS_ERL));
139862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, dde, pwrb,
139962306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
140062306a36Sopenharmony_ci		      dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
140162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, hde, pwrb,
140262306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
140362306a36Sopenharmony_ci		      hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
140462306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
140562306a36Sopenharmony_ci		      ir2t, pwrb,
140662306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
140762306a36Sopenharmony_ci		      ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
140862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, imd, pwrb,
140962306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
141062306a36Sopenharmony_ci		      imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
141162306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
141262306a36Sopenharmony_ci		      data_seq_inorder,
141362306a36Sopenharmony_ci		      pwrb,
141462306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
141562306a36Sopenharmony_ci		      data_seq_inorder) / 32] &
141662306a36Sopenharmony_ci		      OFFLD_PARAMS_DATA_SEQ_INORDER) >> 6);
141762306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
141862306a36Sopenharmony_ci		      pdu_seq_inorder,
141962306a36Sopenharmony_ci		      pwrb,
142062306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
142162306a36Sopenharmony_ci		      pdu_seq_inorder) / 32] &
142262306a36Sopenharmony_ci		      OFFLD_PARAMS_PDU_SEQ_INORDER) >> 7);
142362306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_r2t,
142462306a36Sopenharmony_ci		      pwrb,
142562306a36Sopenharmony_ci		      (params->dw[offsetof(struct amap_beiscsi_offload_params,
142662306a36Sopenharmony_ci		      max_r2t) / 32] &
142762306a36Sopenharmony_ci		      OFFLD_PARAMS_MAX_R2T) >> 8);
142862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, stat_sn,
142962306a36Sopenharmony_ci		      pwrb,
143062306a36Sopenharmony_ci		     (params->dw[offsetof(struct amap_beiscsi_offload_params,
143162306a36Sopenharmony_ci		      exp_statsn) / 32] + 1));
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ciunsigned int beiscsi_invalidate_cxn(struct beiscsi_hba *phba,
143562306a36Sopenharmony_ci				    struct beiscsi_endpoint *beiscsi_ep)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct be_invalidate_connection_params_in *req;
143862306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
143962306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
144062306a36Sopenharmony_ci	unsigned int tag = 0;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
144362306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
144462306a36Sopenharmony_ci	if (!wrb) {
144562306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
144662306a36Sopenharmony_ci		return 0;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	req = embedded_payload(wrb);
145062306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(union be_invalidate_connection_params),
145162306a36Sopenharmony_ci			   true, 0);
145262306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
145362306a36Sopenharmony_ci			   OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION,
145462306a36Sopenharmony_ci			   sizeof(*req));
145562306a36Sopenharmony_ci	req->session_handle = beiscsi_ep->fw_handle;
145662306a36Sopenharmony_ci	req->cid = beiscsi_ep->ep_cid;
145762306a36Sopenharmony_ci	if (beiscsi_ep->conn)
145862306a36Sopenharmony_ci		req->cleanup_type = BE_CLEANUP_TYPE_INVALIDATE;
145962306a36Sopenharmony_ci	else
146062306a36Sopenharmony_ci		req->cleanup_type = BE_CLEANUP_TYPE_ISSUE_TCP_RST;
146162306a36Sopenharmony_ci	/**
146262306a36Sopenharmony_ci	 * 0 - non-persistent targets
146362306a36Sopenharmony_ci	 * 1 - save session info on flash
146462306a36Sopenharmony_ci	 */
146562306a36Sopenharmony_ci	req->save_cfg = 0;
146662306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
146762306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
146862306a36Sopenharmony_ci	return tag;
146962306a36Sopenharmony_ci}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ciunsigned int beiscsi_upload_cxn(struct beiscsi_hba *phba,
147262306a36Sopenharmony_ci				struct beiscsi_endpoint *beiscsi_ep)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
147562306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
147662306a36Sopenharmony_ci	struct be_tcp_upload_params_in *req;
147762306a36Sopenharmony_ci	unsigned int tag;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
148062306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
148162306a36Sopenharmony_ci	if (!wrb) {
148262306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
148362306a36Sopenharmony_ci		return 0;
148462306a36Sopenharmony_ci	}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	req = embedded_payload(wrb);
148762306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, sizeof(union be_tcp_upload_params), true, 0);
148862306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD,
148962306a36Sopenharmony_ci			   OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
149062306a36Sopenharmony_ci	req->id = beiscsi_ep->ep_cid;
149162306a36Sopenharmony_ci	if (beiscsi_ep->conn)
149262306a36Sopenharmony_ci		req->upload_type = BE_UPLOAD_TYPE_GRACEFUL;
149362306a36Sopenharmony_ci	else
149462306a36Sopenharmony_ci		req->upload_type = BE_UPLOAD_TYPE_ABORT;
149562306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
149662306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
149762306a36Sopenharmony_ci	return tag;
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ciint beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
150162306a36Sopenharmony_ci				 struct invldt_cmd_tbl *inv_tbl,
150262306a36Sopenharmony_ci				 unsigned int nents)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	struct be_ctrl_info *ctrl = &phba->ctrl;
150562306a36Sopenharmony_ci	struct invldt_cmds_params_in *req;
150662306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
150762306a36Sopenharmony_ci	struct be_mcc_wrb *wrb;
150862306a36Sopenharmony_ci	unsigned int i, tag;
150962306a36Sopenharmony_ci	struct be_sge *sge;
151062306a36Sopenharmony_ci	int rc;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	if (!nents || nents > BE_INVLDT_CMD_TBL_SZ)
151362306a36Sopenharmony_ci		return -EINVAL;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	nonemb_cmd.size = sizeof(union be_invldt_cmds_params);
151662306a36Sopenharmony_ci	nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
151762306a36Sopenharmony_ci					   nonemb_cmd.size, &nonemb_cmd.dma,
151862306a36Sopenharmony_ci					   GFP_KERNEL);
151962306a36Sopenharmony_ci	if (!nonemb_cmd.va) {
152062306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
152162306a36Sopenharmony_ci			    "BM_%d : invldt_cmds_params alloc failed\n");
152262306a36Sopenharmony_ci		return -ENOMEM;
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	mutex_lock(&ctrl->mbox_lock);
152662306a36Sopenharmony_ci	wrb = alloc_mcc_wrb(phba, &tag);
152762306a36Sopenharmony_ci	if (!wrb) {
152862306a36Sopenharmony_ci		mutex_unlock(&ctrl->mbox_lock);
152962306a36Sopenharmony_ci		dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
153062306a36Sopenharmony_ci				    nonemb_cmd.va, nonemb_cmd.dma);
153162306a36Sopenharmony_ci		return -ENOMEM;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	req = nonemb_cmd.va;
153562306a36Sopenharmony_ci	be_wrb_hdr_prepare(wrb, nonemb_cmd.size, false, 1);
153662306a36Sopenharmony_ci	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
153762306a36Sopenharmony_ci			OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS,
153862306a36Sopenharmony_ci			sizeof(*req));
153962306a36Sopenharmony_ci	req->ref_handle = 0;
154062306a36Sopenharmony_ci	req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
154162306a36Sopenharmony_ci	for (i = 0; i < nents; i++) {
154262306a36Sopenharmony_ci		req->table[i].icd = inv_tbl[i].icd;
154362306a36Sopenharmony_ci		req->table[i].cid = inv_tbl[i].cid;
154462306a36Sopenharmony_ci		req->icd_count++;
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci	sge = nonembedded_sgl(wrb);
154762306a36Sopenharmony_ci	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
154862306a36Sopenharmony_ci	sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma));
154962306a36Sopenharmony_ci	sge->len = cpu_to_le32(nonemb_cmd.size);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	be_mcc_notify(phba, tag);
155262306a36Sopenharmony_ci	mutex_unlock(&ctrl->mbox_lock);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
155562306a36Sopenharmony_ci	if (rc != -EBUSY)
155662306a36Sopenharmony_ci		dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
155762306a36Sopenharmony_ci				    nonemb_cmd.va, nonemb_cmd.dma);
155862306a36Sopenharmony_ci	return rc;
155962306a36Sopenharmony_ci}
1560