162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI
462306a36Sopenharmony_ci * Host Bus Adapters. Refer to the README file included with this package
562306a36Sopenharmony_ci * for driver version and adapter compatibility.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2018 Broadcom. All Rights Reserved.
862306a36Sopenharmony_ci * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Contact Information:
1162306a36Sopenharmony_ci * linux-drivers@broadcom.com
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <scsi/libiscsi.h>
1562306a36Sopenharmony_ci#include <scsi/scsi_transport_iscsi.h>
1662306a36Sopenharmony_ci#include <scsi/scsi_transport.h>
1762306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
1862306a36Sopenharmony_ci#include <scsi/scsi_device.h>
1962306a36Sopenharmony_ci#include <scsi/scsi_host.h>
2062306a36Sopenharmony_ci#include <scsi/scsi_netlink.h>
2162306a36Sopenharmony_ci#include <net/netlink.h>
2262306a36Sopenharmony_ci#include <scsi/scsi.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "be_iscsi.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciextern struct iscsi_transport beiscsi_iscsi_transport;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**
2962306a36Sopenharmony_ci * beiscsi_session_create - creates a new iscsi session
3062306a36Sopenharmony_ci * @ep: pointer to iscsi ep
3162306a36Sopenharmony_ci * @cmds_max: max commands supported
3262306a36Sopenharmony_ci * @qdepth: max queue depth supported
3362306a36Sopenharmony_ci * @initial_cmdsn: initial iscsi CMDSN
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_cistruct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
3662306a36Sopenharmony_ci						 u16 cmds_max,
3762306a36Sopenharmony_ci						 u16 qdepth,
3862306a36Sopenharmony_ci						 u32 initial_cmdsn)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct Scsi_Host *shost;
4162306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep;
4262306a36Sopenharmony_ci	struct iscsi_cls_session *cls_session;
4362306a36Sopenharmony_ci	struct beiscsi_hba *phba;
4462306a36Sopenharmony_ci	struct iscsi_session *sess;
4562306a36Sopenharmony_ci	struct beiscsi_session *beiscsi_sess;
4662306a36Sopenharmony_ci	struct beiscsi_io_task *io_task;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (!ep) {
5062306a36Sopenharmony_ci		pr_err("beiscsi_session_create: invalid ep\n");
5162306a36Sopenharmony_ci		return NULL;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	beiscsi_ep = ep->dd_data;
5462306a36Sopenharmony_ci	phba = beiscsi_ep->phba;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
5762306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
5862306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
5962306a36Sopenharmony_ci		return NULL;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
6362306a36Sopenharmony_ci		    "BS_%d : In beiscsi_session_create\n");
6462306a36Sopenharmony_ci	if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
6562306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
6662306a36Sopenharmony_ci			    "BS_%d : Cannot handle %d cmds."
6762306a36Sopenharmony_ci			    "Max cmds per session supported is %d. Using %d."
6862306a36Sopenharmony_ci			    "\n", cmds_max,
6962306a36Sopenharmony_ci			    beiscsi_ep->phba->params.wrbs_per_cxn,
7062306a36Sopenharmony_ci			    beiscsi_ep->phba->params.wrbs_per_cxn);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	shost = phba->shost;
7662306a36Sopenharmony_ci	cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
7762306a36Sopenharmony_ci					  shost, cmds_max,
7862306a36Sopenharmony_ci					  sizeof(*beiscsi_sess),
7962306a36Sopenharmony_ci					  sizeof(*io_task),
8062306a36Sopenharmony_ci					  initial_cmdsn, ISCSI_MAX_TARGET);
8162306a36Sopenharmony_ci	if (!cls_session)
8262306a36Sopenharmony_ci		return NULL;
8362306a36Sopenharmony_ci	sess = cls_session->dd_data;
8462306a36Sopenharmony_ci	beiscsi_sess = sess->dd_data;
8562306a36Sopenharmony_ci	beiscsi_sess->bhs_pool =  dma_pool_create("beiscsi_bhs_pool",
8662306a36Sopenharmony_ci						   &phba->pcidev->dev,
8762306a36Sopenharmony_ci						   sizeof(struct be_cmd_bhs),
8862306a36Sopenharmony_ci						   64, 0);
8962306a36Sopenharmony_ci	if (!beiscsi_sess->bhs_pool)
9062306a36Sopenharmony_ci		goto destroy_sess;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return cls_session;
9362306a36Sopenharmony_cidestroy_sess:
9462306a36Sopenharmony_ci	iscsi_session_teardown(cls_session);
9562306a36Sopenharmony_ci	return NULL;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/**
9962306a36Sopenharmony_ci * beiscsi_session_destroy - destroys iscsi session
10062306a36Sopenharmony_ci * @cls_session:	pointer to iscsi cls session
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * Destroys iSCSI session instance and releases
10362306a36Sopenharmony_ci * resources allocated for it.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_civoid beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct iscsi_session *sess = cls_session->dd_data;
10862306a36Sopenharmony_ci	struct beiscsi_session *beiscsi_sess = sess->dd_data;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	printk(KERN_INFO "In beiscsi_session_destroy\n");
11162306a36Sopenharmony_ci	dma_pool_destroy(beiscsi_sess->bhs_pool);
11262306a36Sopenharmony_ci	iscsi_session_teardown(cls_session);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * beiscsi_session_fail(): Closing session with appropriate error
11762306a36Sopenharmony_ci * @cls_session: ptr to session
11862306a36Sopenharmony_ci **/
11962306a36Sopenharmony_civoid beiscsi_session_fail(struct iscsi_cls_session *cls_session)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/**
12662306a36Sopenharmony_ci * beiscsi_conn_create - create an instance of iscsi connection
12762306a36Sopenharmony_ci * @cls_session: ptr to iscsi_cls_session
12862306a36Sopenharmony_ci * @cid: iscsi cid
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_cistruct iscsi_cls_conn *
13162306a36Sopenharmony_cibeiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct beiscsi_hba *phba;
13462306a36Sopenharmony_ci	struct Scsi_Host *shost;
13562306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
13662306a36Sopenharmony_ci	struct beiscsi_conn *beiscsi_conn;
13762306a36Sopenharmony_ci	struct iscsi_conn *conn;
13862306a36Sopenharmony_ci	struct iscsi_session *sess;
13962306a36Sopenharmony_ci	struct beiscsi_session *beiscsi_sess;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	shost = iscsi_session_to_shost(cls_session);
14262306a36Sopenharmony_ci	phba = iscsi_host_priv(shost);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
14562306a36Sopenharmony_ci		    "BS_%d : In beiscsi_conn_create ,cid"
14662306a36Sopenharmony_ci		    "from iscsi layer=%d\n", cid);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);
14962306a36Sopenharmony_ci	if (!cls_conn)
15062306a36Sopenharmony_ci		return NULL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	conn = cls_conn->dd_data;
15362306a36Sopenharmony_ci	beiscsi_conn = conn->dd_data;
15462306a36Sopenharmony_ci	beiscsi_conn->ep = NULL;
15562306a36Sopenharmony_ci	beiscsi_conn->phba = phba;
15662306a36Sopenharmony_ci	beiscsi_conn->conn = conn;
15762306a36Sopenharmony_ci	sess = cls_session->dd_data;
15862306a36Sopenharmony_ci	beiscsi_sess = sess->dd_data;
15962306a36Sopenharmony_ci	beiscsi_conn->beiscsi_sess = beiscsi_sess;
16062306a36Sopenharmony_ci	return cls_conn;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
16562306a36Sopenharmony_ci * @cls_session: pointer to iscsi cls session
16662306a36Sopenharmony_ci * @cls_conn: pointer to iscsi cls conn
16762306a36Sopenharmony_ci * @transport_fd: EP handle(64 bit)
16862306a36Sopenharmony_ci * @is_leading: indicate if this is the session leading connection (MCS)
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * This function binds the TCP Conn with iSCSI Connection and Session.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_ciint beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
17362306a36Sopenharmony_ci		      struct iscsi_cls_conn *cls_conn,
17462306a36Sopenharmony_ci		      u64 transport_fd, int is_leading)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct iscsi_conn *conn = cls_conn->dd_data;
17762306a36Sopenharmony_ci	struct beiscsi_conn *beiscsi_conn = conn->dd_data;
17862306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
17962306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
18062306a36Sopenharmony_ci	struct hwi_controller *phwi_ctrlr = phba->phwi_ctrlr;
18162306a36Sopenharmony_ci	struct hwi_wrb_context *pwrb_context;
18262306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep;
18362306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
18462306a36Sopenharmony_ci	uint16_t cri_index;
18562306a36Sopenharmony_ci	int rc = 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	ep = iscsi_lookup_endpoint(transport_fd);
18862306a36Sopenharmony_ci	if (!ep)
18962306a36Sopenharmony_ci		return -EINVAL;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	beiscsi_ep = ep->dd_data;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
19462306a36Sopenharmony_ci		rc = -EINVAL;
19562306a36Sopenharmony_ci		goto put_ep;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (beiscsi_ep->phba != phba) {
19962306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
20062306a36Sopenharmony_ci			    "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",
20162306a36Sopenharmony_ci			    beiscsi_ep->phba, phba);
20262306a36Sopenharmony_ci		rc = -EEXIST;
20362306a36Sopenharmony_ci		goto put_ep;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci	cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
20662306a36Sopenharmony_ci	if (phba->conn_table[cri_index]) {
20762306a36Sopenharmony_ci		if (beiscsi_conn != phba->conn_table[cri_index] ||
20862306a36Sopenharmony_ci		    beiscsi_ep != phba->conn_table[cri_index]->ep) {
20962306a36Sopenharmony_ci			__beiscsi_log(phba, KERN_ERR,
21062306a36Sopenharmony_ci				      "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n",
21162306a36Sopenharmony_ci				      cri_index,
21262306a36Sopenharmony_ci				      beiscsi_ep->ep_cid,
21362306a36Sopenharmony_ci				      beiscsi_conn,
21462306a36Sopenharmony_ci				      phba->conn_table[cri_index]);
21562306a36Sopenharmony_ci			rc = -EINVAL;
21662306a36Sopenharmony_ci			goto put_ep;
21762306a36Sopenharmony_ci		}
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
22162306a36Sopenharmony_ci	beiscsi_conn->ep = beiscsi_ep;
22262306a36Sopenharmony_ci	beiscsi_ep->conn = beiscsi_conn;
22362306a36Sopenharmony_ci	/**
22462306a36Sopenharmony_ci	 * Each connection is associated with a WRBQ kept in wrb_context.
22562306a36Sopenharmony_ci	 * Store doorbell offset for transmit path.
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci	pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
22862306a36Sopenharmony_ci	beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset;
22962306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
23062306a36Sopenharmony_ci		    "BS_%d : cid %d phba->conn_table[%u]=%p\n",
23162306a36Sopenharmony_ci		    beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
23262306a36Sopenharmony_ci	phba->conn_table[cri_index] = beiscsi_conn;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciput_ep:
23562306a36Sopenharmony_ci	iscsi_put_endpoint(ep);
23662306a36Sopenharmony_ci	return rc;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	if (phba->ipv4_iface)
24262306a36Sopenharmony_ci		return 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	phba->ipv4_iface = iscsi_create_iface(phba->shost,
24562306a36Sopenharmony_ci					      &beiscsi_iscsi_transport,
24662306a36Sopenharmony_ci					      ISCSI_IFACE_TYPE_IPV4,
24762306a36Sopenharmony_ci					      0, 0);
24862306a36Sopenharmony_ci	if (!phba->ipv4_iface) {
24962306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
25062306a36Sopenharmony_ci			    "BS_%d : Could not "
25162306a36Sopenharmony_ci			    "create default IPv4 address.\n");
25262306a36Sopenharmony_ci		return -ENODEV;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int beiscsi_iface_create_ipv6(struct beiscsi_hba *phba)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	if (phba->ipv6_iface)
26162306a36Sopenharmony_ci		return 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	phba->ipv6_iface = iscsi_create_iface(phba->shost,
26462306a36Sopenharmony_ci					      &beiscsi_iscsi_transport,
26562306a36Sopenharmony_ci					      ISCSI_IFACE_TYPE_IPV6,
26662306a36Sopenharmony_ci					      0, 0);
26762306a36Sopenharmony_ci	if (!phba->ipv6_iface) {
26862306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
26962306a36Sopenharmony_ci			    "BS_%d : Could not "
27062306a36Sopenharmony_ci			    "create default IPv6 address.\n");
27162306a36Sopenharmony_ci		return -ENODEV;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_civoid beiscsi_iface_create_default(struct beiscsi_hba *phba)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct be_cmd_get_if_info_resp *if_info;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V4, &if_info)) {
28262306a36Sopenharmony_ci		beiscsi_iface_create_ipv4(phba);
28362306a36Sopenharmony_ci		kfree(if_info);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V6, &if_info)) {
28762306a36Sopenharmony_ci		beiscsi_iface_create_ipv6(phba);
28862306a36Sopenharmony_ci		kfree(if_info);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_civoid beiscsi_iface_destroy_default(struct beiscsi_hba *phba)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	if (phba->ipv6_iface) {
29562306a36Sopenharmony_ci		iscsi_destroy_iface(phba->ipv6_iface);
29662306a36Sopenharmony_ci		phba->ipv6_iface = NULL;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	if (phba->ipv4_iface) {
29962306a36Sopenharmony_ci		iscsi_destroy_iface(phba->ipv4_iface);
30062306a36Sopenharmony_ci		phba->ipv4_iface = NULL;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/**
30562306a36Sopenharmony_ci * beiscsi_iface_config_vlan()- Set the VLAN TAG
30662306a36Sopenharmony_ci * @shost: Scsi Host for the driver instance
30762306a36Sopenharmony_ci * @iface_param: Interface paramters
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Set the VLAN TAG for the adapter or disable
31062306a36Sopenharmony_ci * the VLAN config
31162306a36Sopenharmony_ci *
31262306a36Sopenharmony_ci * returns
31362306a36Sopenharmony_ci *	Success: 0
31462306a36Sopenharmony_ci *	Failure: Non-Zero Value
31562306a36Sopenharmony_ci **/
31662306a36Sopenharmony_cistatic int
31762306a36Sopenharmony_cibeiscsi_iface_config_vlan(struct Scsi_Host *shost,
31862306a36Sopenharmony_ci			  struct iscsi_iface_param_info *iface_param)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
32162306a36Sopenharmony_ci	int ret = -EPERM;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	switch (iface_param->param) {
32462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
32562306a36Sopenharmony_ci		ret = 0;
32662306a36Sopenharmony_ci		if (iface_param->value[0] != ISCSI_VLAN_ENABLE)
32762306a36Sopenharmony_ci			ret = beiscsi_if_set_vlan(phba, BEISCSI_VLAN_DISABLE);
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_TAG:
33062306a36Sopenharmony_ci		ret = beiscsi_if_set_vlan(phba,
33162306a36Sopenharmony_ci					  *((uint16_t *)iface_param->value));
33262306a36Sopenharmony_ci		break;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	return ret;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int
33962306a36Sopenharmony_cibeiscsi_iface_config_ipv4(struct Scsi_Host *shost,
34062306a36Sopenharmony_ci			  struct iscsi_iface_param_info *info,
34162306a36Sopenharmony_ci			  void *data, uint32_t dt_len)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
34462306a36Sopenharmony_ci	u8 *ip = NULL, *subnet = NULL, *gw;
34562306a36Sopenharmony_ci	struct nlattr *nla;
34662306a36Sopenharmony_ci	int ret = -EPERM;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Check the param */
34962306a36Sopenharmony_ci	switch (info->param) {
35062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
35162306a36Sopenharmony_ci		if (info->value[0] == ISCSI_IFACE_ENABLE)
35262306a36Sopenharmony_ci			ret = beiscsi_iface_create_ipv4(phba);
35362306a36Sopenharmony_ci		else {
35462306a36Sopenharmony_ci			iscsi_destroy_iface(phba->ipv4_iface);
35562306a36Sopenharmony_ci			phba->ipv4_iface = NULL;
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		break;
35862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GW:
35962306a36Sopenharmony_ci		gw = info->value;
36062306a36Sopenharmony_ci		ret = beiscsi_if_set_gw(phba, BEISCSI_IP_TYPE_V4, gw);
36162306a36Sopenharmony_ci		break;
36262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
36362306a36Sopenharmony_ci		if (info->value[0] == ISCSI_BOOTPROTO_DHCP)
36462306a36Sopenharmony_ci			ret = beiscsi_if_en_dhcp(phba, BEISCSI_IP_TYPE_V4);
36562306a36Sopenharmony_ci		else if (info->value[0] == ISCSI_BOOTPROTO_STATIC)
36662306a36Sopenharmony_ci			/* release DHCP IP address */
36762306a36Sopenharmony_ci			ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
36862306a36Sopenharmony_ci						   NULL, NULL);
36962306a36Sopenharmony_ci		else
37062306a36Sopenharmony_ci			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
37162306a36Sopenharmony_ci				    "BS_%d : Invalid BOOTPROTO: %d\n",
37262306a36Sopenharmony_ci				    info->value[0]);
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_ADDR:
37562306a36Sopenharmony_ci		ip = info->value;
37662306a36Sopenharmony_ci		nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
37762306a36Sopenharmony_ci		if (nla) {
37862306a36Sopenharmony_ci			info = nla_data(nla);
37962306a36Sopenharmony_ci			subnet = info->value;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
38262306a36Sopenharmony_ci					   ip, subnet);
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_SUBNET:
38562306a36Sopenharmony_ci		/*
38662306a36Sopenharmony_ci		 * OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR ioctl needs IP
38762306a36Sopenharmony_ci		 * and subnet both. Find IP to be applied for this subnet.
38862306a36Sopenharmony_ci		 */
38962306a36Sopenharmony_ci		subnet = info->value;
39062306a36Sopenharmony_ci		nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
39162306a36Sopenharmony_ci		if (nla) {
39262306a36Sopenharmony_ci			info = nla_data(nla);
39362306a36Sopenharmony_ci			ip = info->value;
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
39662306a36Sopenharmony_ci					   ip, subnet);
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return ret;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int
40462306a36Sopenharmony_cibeiscsi_iface_config_ipv6(struct Scsi_Host *shost,
40562306a36Sopenharmony_ci			  struct iscsi_iface_param_info *iface_param,
40662306a36Sopenharmony_ci			  void *data, uint32_t dt_len)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
40962306a36Sopenharmony_ci	int ret = -EPERM;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	switch (iface_param->param) {
41262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
41362306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
41462306a36Sopenharmony_ci			ret = beiscsi_iface_create_ipv6(phba);
41562306a36Sopenharmony_ci		else {
41662306a36Sopenharmony_ci			iscsi_destroy_iface(phba->ipv6_iface);
41762306a36Sopenharmony_ci			phba->ipv6_iface = NULL;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR:
42162306a36Sopenharmony_ci		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V6,
42262306a36Sopenharmony_ci					   iface_param->value, NULL);
42362306a36Sopenharmony_ci		break;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return ret;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ciint beiscsi_iface_set_param(struct Scsi_Host *shost,
43062306a36Sopenharmony_ci			    void *data, uint32_t dt_len)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct iscsi_iface_param_info *iface_param = NULL;
43362306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
43462306a36Sopenharmony_ci	struct nlattr *attrib;
43562306a36Sopenharmony_ci	uint32_t rm_len = dt_len;
43662306a36Sopenharmony_ci	int ret;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
43962306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
44062306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
44162306a36Sopenharmony_ci		return -EBUSY;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/* update interface_handle */
44562306a36Sopenharmony_ci	ret = beiscsi_if_get_handle(phba);
44662306a36Sopenharmony_ci	if (ret) {
44762306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
44862306a36Sopenharmony_ci			    "BS_%d : Getting Interface Handle Failed\n");
44962306a36Sopenharmony_ci		return ret;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	nla_for_each_attr(attrib, data, dt_len, rm_len) {
45362306a36Sopenharmony_ci		/* ignore nla_type as it is never used */
45462306a36Sopenharmony_ci		if (nla_len(attrib) < sizeof(*iface_param))
45562306a36Sopenharmony_ci			return -EINVAL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		iface_param = nla_data(attrib);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (iface_param->param_type != ISCSI_NET_PARAM)
46062306a36Sopenharmony_ci			continue;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		/*
46362306a36Sopenharmony_ci		 * BE2ISCSI only supports 1 interface
46462306a36Sopenharmony_ci		 */
46562306a36Sopenharmony_ci		if (iface_param->iface_num) {
46662306a36Sopenharmony_ci			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
46762306a36Sopenharmony_ci				    "BS_%d : Invalid iface_num %d."
46862306a36Sopenharmony_ci				    "Only iface_num 0 is supported.\n",
46962306a36Sopenharmony_ci				    iface_param->iface_num);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci			return -EINVAL;
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
47562306a36Sopenharmony_ci			    "BS_%d : %s.0 set param %d",
47662306a36Sopenharmony_ci			    (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ?
47762306a36Sopenharmony_ci			    "ipv4" : "ipv6", iface_param->param);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		ret = -EPERM;
48062306a36Sopenharmony_ci		switch (iface_param->param) {
48162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
48262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_TAG:
48362306a36Sopenharmony_ci			ret = beiscsi_iface_config_vlan(shost, iface_param);
48462306a36Sopenharmony_ci			break;
48562306a36Sopenharmony_ci		default:
48662306a36Sopenharmony_ci			switch (iface_param->iface_type) {
48762306a36Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV4:
48862306a36Sopenharmony_ci				ret = beiscsi_iface_config_ipv4(shost,
48962306a36Sopenharmony_ci								iface_param,
49062306a36Sopenharmony_ci								data, dt_len);
49162306a36Sopenharmony_ci				break;
49262306a36Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV6:
49362306a36Sopenharmony_ci				ret = beiscsi_iface_config_ipv6(shost,
49462306a36Sopenharmony_ci								iface_param,
49562306a36Sopenharmony_ci								data, dt_len);
49662306a36Sopenharmony_ci				break;
49762306a36Sopenharmony_ci			}
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		if (ret == -EPERM) {
50162306a36Sopenharmony_ci			__beiscsi_log(phba, KERN_ERR,
50262306a36Sopenharmony_ci				      "BS_%d : %s.0 set param %d not permitted",
50362306a36Sopenharmony_ci				      (iface_param->iface_type ==
50462306a36Sopenharmony_ci				       ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6",
50562306a36Sopenharmony_ci				      iface_param->param);
50662306a36Sopenharmony_ci			ret = 0;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci		if (ret)
50962306a36Sopenharmony_ci			break;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return ret;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int __beiscsi_iface_get_param(struct beiscsi_hba *phba,
51662306a36Sopenharmony_ci				     struct iscsi_iface *iface,
51762306a36Sopenharmony_ci				     int param, char *buf)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct be_cmd_get_if_info_resp *if_info;
52062306a36Sopenharmony_ci	int len, ip_type = BEISCSI_IP_TYPE_V4;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
52362306a36Sopenharmony_ci		ip_type = BEISCSI_IP_TYPE_V6;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	len = beiscsi_if_get_info(phba, ip_type, &if_info);
52662306a36Sopenharmony_ci	if (len)
52762306a36Sopenharmony_ci		return len;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	switch (param) {
53062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_ADDR:
53162306a36Sopenharmony_ci		len = sprintf(buf, "%pI4\n", if_info->ip_addr.addr);
53262306a36Sopenharmony_ci		break;
53362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR:
53462306a36Sopenharmony_ci		len = sprintf(buf, "%pI6\n", if_info->ip_addr.addr);
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
53762306a36Sopenharmony_ci		if (!if_info->dhcp_state)
53862306a36Sopenharmony_ci			len = sprintf(buf, "static\n");
53962306a36Sopenharmony_ci		else
54062306a36Sopenharmony_ci			len = sprintf(buf, "dhcp\n");
54162306a36Sopenharmony_ci		break;
54262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_SUBNET:
54362306a36Sopenharmony_ci		len = sprintf(buf, "%pI4\n", if_info->ip_addr.subnet_mask);
54462306a36Sopenharmony_ci		break;
54562306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
54662306a36Sopenharmony_ci		len = sprintf(buf, "%s\n",
54762306a36Sopenharmony_ci			      (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) ?
54862306a36Sopenharmony_ci			      "disable" : "enable");
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ID:
55162306a36Sopenharmony_ci		if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
55262306a36Sopenharmony_ci			len = -EINVAL;
55362306a36Sopenharmony_ci		else
55462306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
55562306a36Sopenharmony_ci				      (if_info->vlan_priority &
55662306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_ID));
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_PRIORITY:
55962306a36Sopenharmony_ci		if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
56062306a36Sopenharmony_ci			len = -EINVAL;
56162306a36Sopenharmony_ci		else
56262306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
56362306a36Sopenharmony_ci				      ((if_info->vlan_priority >> 13) &
56462306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_PRIORITY));
56562306a36Sopenharmony_ci		break;
56662306a36Sopenharmony_ci	default:
56762306a36Sopenharmony_ci		WARN_ON(1);
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	kfree(if_info);
57162306a36Sopenharmony_ci	return len;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciint beiscsi_iface_get_param(struct iscsi_iface *iface,
57562306a36Sopenharmony_ci			    enum iscsi_param_type param_type,
57662306a36Sopenharmony_ci			    int param, char *buf)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
57962306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
58062306a36Sopenharmony_ci	struct be_cmd_get_def_gateway_resp gateway;
58162306a36Sopenharmony_ci	int len = -EPERM;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (param_type != ISCSI_NET_PARAM)
58462306a36Sopenharmony_ci		return 0;
58562306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
58662306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
58762306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
58862306a36Sopenharmony_ci		return -EBUSY;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	switch (param) {
59262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_ADDR:
59362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_SUBNET:
59462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
59562306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR:
59662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
59762306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ID:
59862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_PRIORITY:
59962306a36Sopenharmony_ci		len = __beiscsi_iface_get_param(phba, iface, param, buf);
60062306a36Sopenharmony_ci		break;
60162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
60262306a36Sopenharmony_ci		if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
60362306a36Sopenharmony_ci			len = sprintf(buf, "%s\n",
60462306a36Sopenharmony_ci				      phba->ipv4_iface ? "enable" : "disable");
60562306a36Sopenharmony_ci		else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
60662306a36Sopenharmony_ci			len = sprintf(buf, "%s\n",
60762306a36Sopenharmony_ci				      phba->ipv6_iface ? "enable" : "disable");
60862306a36Sopenharmony_ci		break;
60962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GW:
61062306a36Sopenharmony_ci		memset(&gateway, 0, sizeof(gateway));
61162306a36Sopenharmony_ci		len = beiscsi_if_get_gw(phba, BEISCSI_IP_TYPE_V4, &gateway);
61262306a36Sopenharmony_ci		if (!len)
61362306a36Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr);
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return len;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/**
62162306a36Sopenharmony_ci * beiscsi_ep_get_param - get the iscsi parameter
62262306a36Sopenharmony_ci * @ep: pointer to iscsi ep
62362306a36Sopenharmony_ci * @param: parameter type identifier
62462306a36Sopenharmony_ci * @buf: buffer pointer
62562306a36Sopenharmony_ci *
62662306a36Sopenharmony_ci * returns iscsi parameter
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ciint beiscsi_ep_get_param(struct iscsi_endpoint *ep,
62962306a36Sopenharmony_ci			   enum iscsi_param param, char *buf)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
63262306a36Sopenharmony_ci	int len;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	beiscsi_log(beiscsi_ep->phba, KERN_INFO,
63562306a36Sopenharmony_ci		    BEISCSI_LOG_CONFIG,
63662306a36Sopenharmony_ci		    "BS_%d : In beiscsi_ep_get_param,"
63762306a36Sopenharmony_ci		    " param= %d\n", param);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	switch (param) {
64062306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_PORT:
64162306a36Sopenharmony_ci		len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
64262306a36Sopenharmony_ci		break;
64362306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_ADDRESS:
64462306a36Sopenharmony_ci		if (beiscsi_ep->ip_type == BEISCSI_IP_TYPE_V4)
64562306a36Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
64662306a36Sopenharmony_ci		else
64762306a36Sopenharmony_ci			len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
64862306a36Sopenharmony_ci		break;
64962306a36Sopenharmony_ci	default:
65062306a36Sopenharmony_ci		len = -EPERM;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	return len;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ciint beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
65662306a36Sopenharmony_ci		      enum iscsi_param param, char *buf, int buflen)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct iscsi_conn *conn = cls_conn->dd_data;
65962306a36Sopenharmony_ci	struct iscsi_session *session = conn->session;
66062306a36Sopenharmony_ci	struct beiscsi_hba *phba = NULL;
66162306a36Sopenharmony_ci	int ret;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
66462306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
66562306a36Sopenharmony_ci		    "BS_%d : In beiscsi_conn_set_param,"
66662306a36Sopenharmony_ci		    " param= %d\n", param);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	ret = iscsi_set_param(cls_conn, param, buf, buflen);
66962306a36Sopenharmony_ci	if (ret)
67062306a36Sopenharmony_ci		return ret;
67162306a36Sopenharmony_ci	/*
67262306a36Sopenharmony_ci	 * If userspace tried to set the value to higher than we can
67362306a36Sopenharmony_ci	 * support override here.
67462306a36Sopenharmony_ci	 */
67562306a36Sopenharmony_ci	switch (param) {
67662306a36Sopenharmony_ci	case ISCSI_PARAM_FIRST_BURST:
67762306a36Sopenharmony_ci		if (session->first_burst > 8192)
67862306a36Sopenharmony_ci			session->first_burst = 8192;
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci	case ISCSI_PARAM_MAX_RECV_DLENGTH:
68162306a36Sopenharmony_ci		if (conn->max_recv_dlength > 65536)
68262306a36Sopenharmony_ci			conn->max_recv_dlength = 65536;
68362306a36Sopenharmony_ci		break;
68462306a36Sopenharmony_ci	case ISCSI_PARAM_MAX_BURST:
68562306a36Sopenharmony_ci		if (session->max_burst > 262144)
68662306a36Sopenharmony_ci			session->max_burst = 262144;
68762306a36Sopenharmony_ci		break;
68862306a36Sopenharmony_ci	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
68962306a36Sopenharmony_ci		if (conn->max_xmit_dlength > 65536)
69062306a36Sopenharmony_ci			conn->max_xmit_dlength = 65536;
69162306a36Sopenharmony_ci		fallthrough;
69262306a36Sopenharmony_ci	default:
69362306a36Sopenharmony_ci		return 0;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return 0;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci/**
70062306a36Sopenharmony_ci * beiscsi_get_port_state - Get the Port State
70162306a36Sopenharmony_ci * @shost : pointer to scsi_host structure
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci */
70462306a36Sopenharmony_cistatic void beiscsi_get_port_state(struct Scsi_Host *shost)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
70762306a36Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	ihost->port_state = test_bit(BEISCSI_HBA_LINK_UP, &phba->state) ?
71062306a36Sopenharmony_ci		ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci/**
71462306a36Sopenharmony_ci * beiscsi_get_port_speed  - Get the Port Speed from Adapter
71562306a36Sopenharmony_ci * @shost : pointer to scsi_host structure
71662306a36Sopenharmony_ci *
71762306a36Sopenharmony_ci */
71862306a36Sopenharmony_cistatic void beiscsi_get_port_speed(struct Scsi_Host *shost)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
72162306a36Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	switch (phba->port_speed) {
72462306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_10MBPS:
72562306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
72662306a36Sopenharmony_ci		break;
72762306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_100MBPS:
72862306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_100MBPS;
72962306a36Sopenharmony_ci		break;
73062306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_1GBPS:
73162306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;
73262306a36Sopenharmony_ci		break;
73362306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_10GBPS:
73462306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;
73562306a36Sopenharmony_ci		break;
73662306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_25GBPS:
73762306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_25GBPS;
73862306a36Sopenharmony_ci		break;
73962306a36Sopenharmony_ci	case BE2ISCSI_LINK_SPEED_40GBPS:
74062306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_40GBPS;
74162306a36Sopenharmony_ci		break;
74262306a36Sopenharmony_ci	default:
74362306a36Sopenharmony_ci		ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci/**
74862306a36Sopenharmony_ci * beiscsi_get_host_param - get the iscsi parameter
74962306a36Sopenharmony_ci * @shost: pointer to scsi_host structure
75062306a36Sopenharmony_ci * @param: parameter type identifier
75162306a36Sopenharmony_ci * @buf: buffer pointer
75262306a36Sopenharmony_ci *
75362306a36Sopenharmony_ci */
75462306a36Sopenharmony_ciint beiscsi_get_host_param(struct Scsi_Host *shost,
75562306a36Sopenharmony_ci			   enum iscsi_host_param param, char *buf)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct beiscsi_hba *phba = iscsi_host_priv(shost);
75862306a36Sopenharmony_ci	int status = 0;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
76162306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
76262306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
76662306a36Sopenharmony_ci		    "BS_%d : In beiscsi_get_host_param, param = %d\n", param);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	switch (param) {
76962306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_HWADDRESS:
77062306a36Sopenharmony_ci		status = beiscsi_get_macaddr(buf, phba);
77162306a36Sopenharmony_ci		if (status < 0) {
77262306a36Sopenharmony_ci			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
77362306a36Sopenharmony_ci				    "BS_%d : beiscsi_get_macaddr Failed\n");
77462306a36Sopenharmony_ci			return 0;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci		break;
77762306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_INITIATOR_NAME:
77862306a36Sopenharmony_ci		/* try fetching user configured name first */
77962306a36Sopenharmony_ci		status = beiscsi_get_initiator_name(phba, buf, true);
78062306a36Sopenharmony_ci		if (status < 0) {
78162306a36Sopenharmony_ci			status = beiscsi_get_initiator_name(phba, buf, false);
78262306a36Sopenharmony_ci			if (status < 0) {
78362306a36Sopenharmony_ci				beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
78462306a36Sopenharmony_ci					    "BS_%d : Retrieving Initiator Name Failed\n");
78562306a36Sopenharmony_ci				status = 0;
78662306a36Sopenharmony_ci			}
78762306a36Sopenharmony_ci		}
78862306a36Sopenharmony_ci		break;
78962306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_STATE:
79062306a36Sopenharmony_ci		beiscsi_get_port_state(shost);
79162306a36Sopenharmony_ci		status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
79262306a36Sopenharmony_ci		break;
79362306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_SPEED:
79462306a36Sopenharmony_ci		beiscsi_get_port_speed(shost);
79562306a36Sopenharmony_ci		status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
79662306a36Sopenharmony_ci		break;
79762306a36Sopenharmony_ci	default:
79862306a36Sopenharmony_ci		return iscsi_host_get_param(shost, param, buf);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci	return status;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ciint beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct be_cmd_get_nic_conf_resp resp;
80662306a36Sopenharmony_ci	int rc;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (phba->mac_addr_set)
80962306a36Sopenharmony_ci		return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	memset(&resp, 0, sizeof(resp));
81262306a36Sopenharmony_ci	rc = mgmt_get_nic_conf(phba, &resp);
81362306a36Sopenharmony_ci	if (rc)
81462306a36Sopenharmony_ci		return rc;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	phba->mac_addr_set = true;
81762306a36Sopenharmony_ci	memcpy(phba->mac_address, resp.mac_address, ETH_ALEN);
81862306a36Sopenharmony_ci	return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci/**
82262306a36Sopenharmony_ci * beiscsi_conn_get_stats - get the iscsi stats
82362306a36Sopenharmony_ci * @cls_conn: pointer to iscsi cls conn
82462306a36Sopenharmony_ci * @stats: pointer to iscsi_stats structure
82562306a36Sopenharmony_ci *
82662306a36Sopenharmony_ci * returns iscsi stats
82762306a36Sopenharmony_ci */
82862306a36Sopenharmony_civoid beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
82962306a36Sopenharmony_ci			    struct iscsi_stats *stats)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct iscsi_conn *conn = cls_conn->dd_data;
83262306a36Sopenharmony_ci	struct beiscsi_hba *phba = NULL;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
83562306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
83662306a36Sopenharmony_ci		    "BS_%d : In beiscsi_conn_get_stats\n");
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	stats->txdata_octets = conn->txdata_octets;
83962306a36Sopenharmony_ci	stats->rxdata_octets = conn->rxdata_octets;
84062306a36Sopenharmony_ci	stats->dataout_pdus = conn->dataout_pdus_cnt;
84162306a36Sopenharmony_ci	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
84262306a36Sopenharmony_ci	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
84362306a36Sopenharmony_ci	stats->datain_pdus = conn->datain_pdus_cnt;
84462306a36Sopenharmony_ci	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
84562306a36Sopenharmony_ci	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
84662306a36Sopenharmony_ci	stats->r2t_pdus = conn->r2t_pdus_cnt;
84762306a36Sopenharmony_ci	stats->digest_err = 0;
84862306a36Sopenharmony_ci	stats->timeout_err = 0;
84962306a36Sopenharmony_ci	stats->custom_length = 1;
85062306a36Sopenharmony_ci	strcpy(stats->custom[0].desc, "eh_abort_cnt");
85162306a36Sopenharmony_ci	stats->custom[0].value = conn->eh_abort_cnt;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci/**
85562306a36Sopenharmony_ci * beiscsi_set_params_for_offld - get the parameters for offload
85662306a36Sopenharmony_ci * @beiscsi_conn: pointer to beiscsi_conn
85762306a36Sopenharmony_ci * @params: pointer to offload_params structure
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_cistatic void  beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
86062306a36Sopenharmony_ci					  struct beiscsi_offload_params *params)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct iscsi_conn *conn = beiscsi_conn->conn;
86362306a36Sopenharmony_ci	struct iscsi_session *session = conn->session;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,
86662306a36Sopenharmony_ci		      params, session->max_burst);
86762306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params,
86862306a36Sopenharmony_ci		      max_send_data_segment_length, params,
86962306a36Sopenharmony_ci		      conn->max_xmit_dlength);
87062306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,
87162306a36Sopenharmony_ci		      params, session->first_burst);
87262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,
87362306a36Sopenharmony_ci		      session->erl);
87462306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,
87562306a36Sopenharmony_ci		      conn->datadgst_en);
87662306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,
87762306a36Sopenharmony_ci		      conn->hdrdgst_en);
87862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,
87962306a36Sopenharmony_ci		      session->initial_r2t_en);
88062306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
88162306a36Sopenharmony_ci		      session->imm_data_en);
88262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params,
88362306a36Sopenharmony_ci		      data_seq_inorder, params,
88462306a36Sopenharmony_ci		      session->dataseq_inorder_en);
88562306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params,
88662306a36Sopenharmony_ci		      pdu_seq_inorder, params,
88762306a36Sopenharmony_ci		      session->pdu_inorder_en);
88862306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_r2t, params,
88962306a36Sopenharmony_ci		      session->max_r2t);
89062306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
89162306a36Sopenharmony_ci		      (conn->exp_statsn - 1));
89262306a36Sopenharmony_ci	AMAP_SET_BITS(struct amap_beiscsi_offload_params,
89362306a36Sopenharmony_ci		      max_recv_data_segment_length, params,
89462306a36Sopenharmony_ci		      conn->max_recv_dlength);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci/**
89962306a36Sopenharmony_ci * beiscsi_conn_start - offload of session to chip
90062306a36Sopenharmony_ci * @cls_conn: pointer to beiscsi_conn
90162306a36Sopenharmony_ci */
90262306a36Sopenharmony_ciint beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct iscsi_conn *conn = cls_conn->dd_data;
90562306a36Sopenharmony_ci	struct beiscsi_conn *beiscsi_conn = conn->dd_data;
90662306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep;
90762306a36Sopenharmony_ci	struct beiscsi_offload_params params;
90862306a36Sopenharmony_ci	struct beiscsi_hba *phba;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
91362306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
91462306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
91562306a36Sopenharmony_ci		return -EBUSY;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci	beiscsi_log(beiscsi_conn->phba, KERN_INFO, BEISCSI_LOG_CONFIG,
91862306a36Sopenharmony_ci		    "BS_%d : In beiscsi_conn_start\n");
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	memset(&params, 0, sizeof(struct beiscsi_offload_params));
92162306a36Sopenharmony_ci	beiscsi_ep = beiscsi_conn->ep;
92262306a36Sopenharmony_ci	if (!beiscsi_ep)
92362306a36Sopenharmony_ci		beiscsi_log(beiscsi_conn->phba, KERN_ERR,
92462306a36Sopenharmony_ci			    BEISCSI_LOG_CONFIG,
92562306a36Sopenharmony_ci			    "BS_%d : In beiscsi_conn_start , no beiscsi_ep\n");
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	beiscsi_conn->login_in_progress = 0;
92862306a36Sopenharmony_ci	beiscsi_set_params_for_offld(beiscsi_conn, &params);
92962306a36Sopenharmony_ci	beiscsi_offload_connection(beiscsi_conn, &params);
93062306a36Sopenharmony_ci	iscsi_conn_start(cls_conn);
93162306a36Sopenharmony_ci	return 0;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci/**
93562306a36Sopenharmony_ci * beiscsi_get_cid - Allocate a cid
93662306a36Sopenharmony_ci * @phba: The phba instance
93762306a36Sopenharmony_ci */
93862306a36Sopenharmony_cistatic int beiscsi_get_cid(struct beiscsi_hba *phba)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	uint16_t cid_avlbl_ulp0, cid_avlbl_ulp1;
94162306a36Sopenharmony_ci	unsigned short cid, cid_from_ulp;
94262306a36Sopenharmony_ci	struct ulp_cid_info *cid_info;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* Find the ULP which has more CID available */
94562306a36Sopenharmony_ci	cid_avlbl_ulp0 = (phba->cid_array_info[BEISCSI_ULP0]) ?
94662306a36Sopenharmony_ci			  BEISCSI_ULP0_AVLBL_CID(phba) : 0;
94762306a36Sopenharmony_ci	cid_avlbl_ulp1 = (phba->cid_array_info[BEISCSI_ULP1]) ?
94862306a36Sopenharmony_ci			  BEISCSI_ULP1_AVLBL_CID(phba) : 0;
94962306a36Sopenharmony_ci	cid_from_ulp = (cid_avlbl_ulp0 > cid_avlbl_ulp1) ?
95062306a36Sopenharmony_ci			BEISCSI_ULP0 : BEISCSI_ULP1;
95162306a36Sopenharmony_ci	/**
95262306a36Sopenharmony_ci	 * If iSCSI protocol is loaded only on ULP 0, and when cid_avlbl_ulp
95362306a36Sopenharmony_ci	 * is ZERO for both, ULP 1 is returned.
95462306a36Sopenharmony_ci	 * Check if ULP is loaded before getting new CID.
95562306a36Sopenharmony_ci	 */
95662306a36Sopenharmony_ci	if (!test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported))
95762306a36Sopenharmony_ci		return BE_INVALID_CID;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	cid_info = phba->cid_array_info[cid_from_ulp];
96062306a36Sopenharmony_ci	cid = cid_info->cid_array[cid_info->cid_alloc];
96162306a36Sopenharmony_ci	if (!cid_info->avlbl_cids || cid == BE_INVALID_CID) {
96262306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
96362306a36Sopenharmony_ci				"BS_%d : failed to get cid: available %u:%u\n",
96462306a36Sopenharmony_ci				cid_info->avlbl_cids, cid_info->cid_free);
96562306a36Sopenharmony_ci		return BE_INVALID_CID;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci	/* empty the slot */
96862306a36Sopenharmony_ci	cid_info->cid_array[cid_info->cid_alloc++] = BE_INVALID_CID;
96962306a36Sopenharmony_ci	if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(phba, cid_from_ulp))
97062306a36Sopenharmony_ci		cid_info->cid_alloc = 0;
97162306a36Sopenharmony_ci	cid_info->avlbl_cids--;
97262306a36Sopenharmony_ci	return cid;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci/**
97662306a36Sopenharmony_ci * beiscsi_put_cid - Free the cid
97762306a36Sopenharmony_ci * @phba: The phba for which the cid is being freed
97862306a36Sopenharmony_ci * @cid: The cid to free
97962306a36Sopenharmony_ci */
98062306a36Sopenharmony_cistatic void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
98362306a36Sopenharmony_ci	struct hwi_wrb_context *pwrb_context;
98462306a36Sopenharmony_ci	struct hwi_controller *phwi_ctrlr;
98562306a36Sopenharmony_ci	struct ulp_cid_info *cid_info;
98662306a36Sopenharmony_ci	uint16_t cid_post_ulp;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	phwi_ctrlr = phba->phwi_ctrlr;
98962306a36Sopenharmony_ci	pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
99062306a36Sopenharmony_ci	cid_post_ulp = pwrb_context->ulp_num;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	cid_info = phba->cid_array_info[cid_post_ulp];
99362306a36Sopenharmony_ci	/* fill only in empty slot */
99462306a36Sopenharmony_ci	if (cid_info->cid_array[cid_info->cid_free] != BE_INVALID_CID) {
99562306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
99662306a36Sopenharmony_ci			      "BS_%d : failed to put cid %u: available %u:%u\n",
99762306a36Sopenharmony_ci			      cid, cid_info->avlbl_cids, cid_info->cid_free);
99862306a36Sopenharmony_ci		return;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci	cid_info->cid_array[cid_info->cid_free++] = cid;
100162306a36Sopenharmony_ci	if (cid_info->cid_free == BEISCSI_GET_CID_COUNT(phba, cid_post_ulp))
100262306a36Sopenharmony_ci		cid_info->cid_free = 0;
100362306a36Sopenharmony_ci	cid_info->avlbl_cids++;
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci/**
100762306a36Sopenharmony_ci * beiscsi_free_ep - free endpoint
100862306a36Sopenharmony_ci * @beiscsi_ep: pointer to device endpoint struct
100962306a36Sopenharmony_ci */
101062306a36Sopenharmony_cistatic void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct beiscsi_hba *phba = beiscsi_ep->phba;
101362306a36Sopenharmony_ci	struct beiscsi_conn *beiscsi_conn;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
101662306a36Sopenharmony_ci	beiscsi_ep->phba = NULL;
101762306a36Sopenharmony_ci	/* clear this to track freeing in beiscsi_ep_disconnect */
101862306a36Sopenharmony_ci	phba->ep_array[BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid)] = NULL;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/**
102162306a36Sopenharmony_ci	 * Check if any connection resource allocated by driver
102262306a36Sopenharmony_ci	 * is to be freed.This case occurs when target redirection
102362306a36Sopenharmony_ci	 * or connection retry is done.
102462306a36Sopenharmony_ci	 **/
102562306a36Sopenharmony_ci	if (!beiscsi_ep->conn)
102662306a36Sopenharmony_ci		return;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	beiscsi_conn = beiscsi_ep->conn;
102962306a36Sopenharmony_ci	/**
103062306a36Sopenharmony_ci	 * Break ep->conn link here so that completions after
103162306a36Sopenharmony_ci	 * this are ignored.
103262306a36Sopenharmony_ci	 */
103362306a36Sopenharmony_ci	beiscsi_ep->conn = NULL;
103462306a36Sopenharmony_ci	if (beiscsi_conn->login_in_progress) {
103562306a36Sopenharmony_ci		beiscsi_free_mgmt_task_handles(beiscsi_conn,
103662306a36Sopenharmony_ci					       beiscsi_conn->task);
103762306a36Sopenharmony_ci		beiscsi_conn->login_in_progress = 0;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci/**
104262306a36Sopenharmony_ci * beiscsi_open_conn - Ask FW to open a TCP connection
104362306a36Sopenharmony_ci * @ep: pointer to device endpoint struct
104462306a36Sopenharmony_ci * @src_addr: The source IP address
104562306a36Sopenharmony_ci * @dst_addr: The Destination  IP address
104662306a36Sopenharmony_ci * @non_blocking: blocking or non-blocking call
104762306a36Sopenharmony_ci *
104862306a36Sopenharmony_ci * Asks the FW to open a TCP connection
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_cistatic int beiscsi_open_conn(struct iscsi_endpoint *ep,
105162306a36Sopenharmony_ci			     struct sockaddr *src_addr,
105262306a36Sopenharmony_ci			     struct sockaddr *dst_addr, int non_blocking)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
105562306a36Sopenharmony_ci	struct beiscsi_hba *phba = beiscsi_ep->phba;
105662306a36Sopenharmony_ci	struct tcp_connect_and_offload_out *ptcpcnct_out;
105762306a36Sopenharmony_ci	struct be_dma_mem nonemb_cmd;
105862306a36Sopenharmony_ci	unsigned int tag, req_memsize;
105962306a36Sopenharmony_ci	int ret = -ENOMEM;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
106262306a36Sopenharmony_ci		    "BS_%d : In beiscsi_open_conn\n");
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
106562306a36Sopenharmony_ci	if (beiscsi_ep->ep_cid == BE_INVALID_CID) {
106662306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
106762306a36Sopenharmony_ci			    "BS_%d : No free cid available\n");
106862306a36Sopenharmony_ci		return ret;
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
107262306a36Sopenharmony_ci		    "BS_%d : In beiscsi_open_conn, ep_cid=%d\n",
107362306a36Sopenharmony_ci		    beiscsi_ep->ep_cid);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	phba->ep_array[BE_GET_CRI_FROM_CID
107662306a36Sopenharmony_ci		       (beiscsi_ep->ep_cid)] = ep;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	beiscsi_ep->cid_vld = 0;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (is_chip_be2_be3r(phba))
108162306a36Sopenharmony_ci		req_memsize = sizeof(struct tcp_connect_and_offload_in);
108262306a36Sopenharmony_ci	else
108362306a36Sopenharmony_ci		req_memsize = sizeof(struct tcp_connect_and_offload_in_v1);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
108662306a36Sopenharmony_ci				req_memsize,
108762306a36Sopenharmony_ci				&nonemb_cmd.dma, GFP_KERNEL);
108862306a36Sopenharmony_ci	if (nonemb_cmd.va == NULL) {
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
109162306a36Sopenharmony_ci			    "BS_%d : Failed to allocate memory for"
109262306a36Sopenharmony_ci			    " mgmt_open_connection\n");
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		beiscsi_free_ep(beiscsi_ep);
109562306a36Sopenharmony_ci		return -ENOMEM;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci	nonemb_cmd.size = req_memsize;
109862306a36Sopenharmony_ci	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
109962306a36Sopenharmony_ci	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
110062306a36Sopenharmony_ci	if (!tag) {
110162306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
110262306a36Sopenharmony_ci			    "BS_%d : mgmt_open_connection Failed for cid=%d\n",
110362306a36Sopenharmony_ci			    beiscsi_ep->ep_cid);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
110662306a36Sopenharmony_ci				    nonemb_cmd.va, nonemb_cmd.dma);
110762306a36Sopenharmony_ci		beiscsi_free_ep(beiscsi_ep);
110862306a36Sopenharmony_ci		return -EAGAIN;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
111262306a36Sopenharmony_ci	if (ret) {
111362306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR,
111462306a36Sopenharmony_ci			    BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
111562306a36Sopenharmony_ci			    "BS_%d : mgmt_open_connection Failed");
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		if (ret != -EBUSY)
111862306a36Sopenharmony_ci			dma_free_coherent(&phba->ctrl.pdev->dev,
111962306a36Sopenharmony_ci					nonemb_cmd.size, nonemb_cmd.va,
112062306a36Sopenharmony_ci					nonemb_cmd.dma);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		beiscsi_free_ep(beiscsi_ep);
112362306a36Sopenharmony_ci		return ret;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	ptcpcnct_out = (struct tcp_connect_and_offload_out *)nonemb_cmd.va;
112762306a36Sopenharmony_ci	beiscsi_ep = ep->dd_data;
112862306a36Sopenharmony_ci	beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
112962306a36Sopenharmony_ci	beiscsi_ep->cid_vld = 1;
113062306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
113162306a36Sopenharmony_ci		    "BS_%d : mgmt_open_connection Success\n");
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
113462306a36Sopenharmony_ci			    nonemb_cmd.va, nonemb_cmd.dma);
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci/**
113962306a36Sopenharmony_ci * beiscsi_ep_connect - Ask chip to create TCP Conn
114062306a36Sopenharmony_ci * @shost: Pointer to scsi_host structure
114162306a36Sopenharmony_ci * @dst_addr: The IP address of Target
114262306a36Sopenharmony_ci * @non_blocking: blocking or non-blocking call
114362306a36Sopenharmony_ci *
114462306a36Sopenharmony_ci * This routines first asks chip to create a connection and then allocates an EP
114562306a36Sopenharmony_ci */
114662306a36Sopenharmony_cistruct iscsi_endpoint *
114762306a36Sopenharmony_cibeiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
114862306a36Sopenharmony_ci		   int non_blocking)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	struct beiscsi_hba *phba;
115162306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep;
115262306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
115362306a36Sopenharmony_ci	int ret;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (!shost) {
115662306a36Sopenharmony_ci		ret = -ENXIO;
115762306a36Sopenharmony_ci		pr_err("beiscsi_ep_connect shost is NULL\n");
115862306a36Sopenharmony_ci		return ERR_PTR(ret);
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	phba = iscsi_host_priv(shost);
116262306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
116362306a36Sopenharmony_ci		ret = -EIO;
116462306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
116562306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
116662306a36Sopenharmony_ci		return ERR_PTR(ret);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci	if (!test_bit(BEISCSI_HBA_LINK_UP, &phba->state)) {
116962306a36Sopenharmony_ci		ret = -EBUSY;
117062306a36Sopenharmony_ci		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
117162306a36Sopenharmony_ci			    "BS_%d : The Adapter Port state is Down!!!\n");
117262306a36Sopenharmony_ci		return ERR_PTR(ret);
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
117662306a36Sopenharmony_ci	if (!ep) {
117762306a36Sopenharmony_ci		ret = -ENOMEM;
117862306a36Sopenharmony_ci		return ERR_PTR(ret);
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	beiscsi_ep = ep->dd_data;
118262306a36Sopenharmony_ci	beiscsi_ep->phba = phba;
118362306a36Sopenharmony_ci	beiscsi_ep->openiscsi_ep = ep;
118462306a36Sopenharmony_ci	ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking);
118562306a36Sopenharmony_ci	if (ret) {
118662306a36Sopenharmony_ci		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
118762306a36Sopenharmony_ci			    "BS_%d : Failed in beiscsi_open_conn\n");
118862306a36Sopenharmony_ci		goto free_ep;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return ep;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cifree_ep:
119462306a36Sopenharmony_ci	iscsi_destroy_endpoint(ep);
119562306a36Sopenharmony_ci	return ERR_PTR(ret);
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci/**
119962306a36Sopenharmony_ci * beiscsi_ep_poll - Poll to see if connection is established
120062306a36Sopenharmony_ci * @ep:	endpoint to be used
120162306a36Sopenharmony_ci * @timeout_ms: timeout specified in millisecs
120262306a36Sopenharmony_ci *
120362306a36Sopenharmony_ci * Poll to see if TCP connection established
120462306a36Sopenharmony_ci */
120562306a36Sopenharmony_ciint beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	beiscsi_log(beiscsi_ep->phba, KERN_INFO, BEISCSI_LOG_CONFIG,
121062306a36Sopenharmony_ci		    "BS_%d : In  beiscsi_ep_poll\n");
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (beiscsi_ep->cid_vld == 1)
121362306a36Sopenharmony_ci		return 1;
121462306a36Sopenharmony_ci	else
121562306a36Sopenharmony_ci		return 0;
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci/**
121962306a36Sopenharmony_ci * beiscsi_flush_cq()- Flush the CQ created.
122062306a36Sopenharmony_ci * @phba: ptr device priv structure.
122162306a36Sopenharmony_ci *
122262306a36Sopenharmony_ci * Before the connection resource are freed flush
122362306a36Sopenharmony_ci * all the CQ enteries
122462306a36Sopenharmony_ci **/
122562306a36Sopenharmony_cistatic void beiscsi_flush_cq(struct beiscsi_hba *phba)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	uint16_t i;
122862306a36Sopenharmony_ci	struct be_eq_obj *pbe_eq;
122962306a36Sopenharmony_ci	struct hwi_controller *phwi_ctrlr;
123062306a36Sopenharmony_ci	struct hwi_context_memory *phwi_context;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	phwi_ctrlr = phba->phwi_ctrlr;
123362306a36Sopenharmony_ci	phwi_context = phwi_ctrlr->phwi_ctxt;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	for (i = 0; i < phba->num_cpus; i++) {
123662306a36Sopenharmony_ci		pbe_eq = &phwi_context->be_eq[i];
123762306a36Sopenharmony_ci		irq_poll_disable(&pbe_eq->iopoll);
123862306a36Sopenharmony_ci		beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
123962306a36Sopenharmony_ci		irq_poll_enable(&pbe_eq->iopoll);
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci/**
124462306a36Sopenharmony_ci * beiscsi_conn_close - Invalidate and upload connection
124562306a36Sopenharmony_ci * @beiscsi_ep: pointer to device endpoint struct
124662306a36Sopenharmony_ci *
124762306a36Sopenharmony_ci * Returns 0 on success,  -1 on failure.
124862306a36Sopenharmony_ci */
124962306a36Sopenharmony_cistatic int beiscsi_conn_close(struct beiscsi_endpoint *beiscsi_ep)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	struct beiscsi_hba *phba = beiscsi_ep->phba;
125262306a36Sopenharmony_ci	unsigned int tag, attempts;
125362306a36Sopenharmony_ci	int ret;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/**
125662306a36Sopenharmony_ci	 * Without successfully invalidating and uploading connection
125762306a36Sopenharmony_ci	 * driver can't reuse the CID so attempt more than once.
125862306a36Sopenharmony_ci	 */
125962306a36Sopenharmony_ci	attempts = 0;
126062306a36Sopenharmony_ci	while (attempts++ < 3) {
126162306a36Sopenharmony_ci		tag = beiscsi_invalidate_cxn(phba, beiscsi_ep);
126262306a36Sopenharmony_ci		if (tag) {
126362306a36Sopenharmony_ci			ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
126462306a36Sopenharmony_ci			if (!ret)
126562306a36Sopenharmony_ci				break;
126662306a36Sopenharmony_ci			beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
126762306a36Sopenharmony_ci				    "BS_%d : invalidate conn failed cid %d\n",
126862306a36Sopenharmony_ci				    beiscsi_ep->ep_cid);
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/* wait for all completions to arrive, then process them */
127362306a36Sopenharmony_ci	msleep(250);
127462306a36Sopenharmony_ci	/* flush CQ entries */
127562306a36Sopenharmony_ci	beiscsi_flush_cq(phba);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	if (attempts > 3)
127862306a36Sopenharmony_ci		return -1;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	attempts = 0;
128162306a36Sopenharmony_ci	while (attempts++ < 3) {
128262306a36Sopenharmony_ci		tag = beiscsi_upload_cxn(phba, beiscsi_ep);
128362306a36Sopenharmony_ci		if (tag) {
128462306a36Sopenharmony_ci			ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
128562306a36Sopenharmony_ci			if (!ret)
128662306a36Sopenharmony_ci				break;
128762306a36Sopenharmony_ci			beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
128862306a36Sopenharmony_ci				    "BS_%d : upload conn failed cid %d\n",
128962306a36Sopenharmony_ci				    beiscsi_ep->ep_cid);
129062306a36Sopenharmony_ci		}
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci	if (attempts > 3)
129362306a36Sopenharmony_ci		return -1;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	return 0;
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci/**
129962306a36Sopenharmony_ci * beiscsi_ep_disconnect - Tears down the TCP connection
130062306a36Sopenharmony_ci * @ep:	endpoint to be used
130162306a36Sopenharmony_ci *
130262306a36Sopenharmony_ci * Tears down the TCP connection
130362306a36Sopenharmony_ci */
130462306a36Sopenharmony_civoid beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	struct beiscsi_endpoint *beiscsi_ep;
130762306a36Sopenharmony_ci	struct beiscsi_hba *phba;
130862306a36Sopenharmony_ci	uint16_t cri_index;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	beiscsi_ep = ep->dd_data;
131162306a36Sopenharmony_ci	phba = beiscsi_ep->phba;
131262306a36Sopenharmony_ci	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
131362306a36Sopenharmony_ci		    "BS_%d : In beiscsi_ep_disconnect for ep_cid = %u\n",
131462306a36Sopenharmony_ci		    beiscsi_ep->ep_cid);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
131762306a36Sopenharmony_ci	if (!phba->ep_array[cri_index]) {
131862306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
131962306a36Sopenharmony_ci			      "BS_%d : ep_array at %u cid %u empty\n",
132062306a36Sopenharmony_ci			      cri_index,
132162306a36Sopenharmony_ci			      beiscsi_ep->ep_cid);
132262306a36Sopenharmony_ci		return;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (!beiscsi_hba_is_online(phba)) {
132662306a36Sopenharmony_ci		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
132762306a36Sopenharmony_ci			    "BS_%d : HBA in error 0x%lx\n", phba->state);
132862306a36Sopenharmony_ci	} else {
132962306a36Sopenharmony_ci		/**
133062306a36Sopenharmony_ci		 * Make CID available even if close fails.
133162306a36Sopenharmony_ci		 * If not freed, FW might fail open using the CID.
133262306a36Sopenharmony_ci		 */
133362306a36Sopenharmony_ci		if (beiscsi_conn_close(beiscsi_ep) < 0)
133462306a36Sopenharmony_ci			__beiscsi_log(phba, KERN_ERR,
133562306a36Sopenharmony_ci				      "BS_%d : close conn failed cid %d\n",
133662306a36Sopenharmony_ci				      beiscsi_ep->ep_cid);
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	beiscsi_free_ep(beiscsi_ep);
134062306a36Sopenharmony_ci	if (!phba->conn_table[cri_index])
134162306a36Sopenharmony_ci		__beiscsi_log(phba, KERN_ERR,
134262306a36Sopenharmony_ci			      "BS_%d : conn_table empty at %u: cid %u\n",
134362306a36Sopenharmony_ci			      cri_index, beiscsi_ep->ep_cid);
134462306a36Sopenharmony_ci	phba->conn_table[cri_index] = NULL;
134562306a36Sopenharmony_ci	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ciumode_t beiscsi_attr_is_visible(int param_type, int param)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	switch (param_type) {
135162306a36Sopenharmony_ci	case ISCSI_NET_PARAM:
135262306a36Sopenharmony_ci		switch (param) {
135362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IFACE_ENABLE:
135462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_ADDR:
135562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_SUBNET:
135662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
135762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GW:
135862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR:
135962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ID:
136062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_PRIORITY:
136162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
136262306a36Sopenharmony_ci			return S_IRUGO;
136362306a36Sopenharmony_ci		default:
136462306a36Sopenharmony_ci			return 0;
136562306a36Sopenharmony_ci		}
136662306a36Sopenharmony_ci	case ISCSI_HOST_PARAM:
136762306a36Sopenharmony_ci		switch (param) {
136862306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_HWADDRESS:
136962306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_INITIATOR_NAME:
137062306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_STATE:
137162306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_SPEED:
137262306a36Sopenharmony_ci			return S_IRUGO;
137362306a36Sopenharmony_ci		default:
137462306a36Sopenharmony_ci			return 0;
137562306a36Sopenharmony_ci		}
137662306a36Sopenharmony_ci	case ISCSI_PARAM:
137762306a36Sopenharmony_ci		switch (param) {
137862306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_RECV_DLENGTH:
137962306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
138062306a36Sopenharmony_ci		case ISCSI_PARAM_HDRDGST_EN:
138162306a36Sopenharmony_ci		case ISCSI_PARAM_DATADGST_EN:
138262306a36Sopenharmony_ci		case ISCSI_PARAM_CONN_ADDRESS:
138362306a36Sopenharmony_ci		case ISCSI_PARAM_CONN_PORT:
138462306a36Sopenharmony_ci		case ISCSI_PARAM_EXP_STATSN:
138562306a36Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_ADDRESS:
138662306a36Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_PORT:
138762306a36Sopenharmony_ci		case ISCSI_PARAM_PING_TMO:
138862306a36Sopenharmony_ci		case ISCSI_PARAM_RECV_TMO:
138962306a36Sopenharmony_ci		case ISCSI_PARAM_INITIAL_R2T_EN:
139062306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_R2T:
139162306a36Sopenharmony_ci		case ISCSI_PARAM_IMM_DATA_EN:
139262306a36Sopenharmony_ci		case ISCSI_PARAM_FIRST_BURST:
139362306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_BURST:
139462306a36Sopenharmony_ci		case ISCSI_PARAM_PDU_INORDER_EN:
139562306a36Sopenharmony_ci		case ISCSI_PARAM_DATASEQ_INORDER_EN:
139662306a36Sopenharmony_ci		case ISCSI_PARAM_ERL:
139762306a36Sopenharmony_ci		case ISCSI_PARAM_TARGET_NAME:
139862306a36Sopenharmony_ci		case ISCSI_PARAM_TPGT:
139962306a36Sopenharmony_ci		case ISCSI_PARAM_USERNAME:
140062306a36Sopenharmony_ci		case ISCSI_PARAM_PASSWORD:
140162306a36Sopenharmony_ci		case ISCSI_PARAM_USERNAME_IN:
140262306a36Sopenharmony_ci		case ISCSI_PARAM_PASSWORD_IN:
140362306a36Sopenharmony_ci		case ISCSI_PARAM_FAST_ABORT:
140462306a36Sopenharmony_ci		case ISCSI_PARAM_ABORT_TMO:
140562306a36Sopenharmony_ci		case ISCSI_PARAM_LU_RESET_TMO:
140662306a36Sopenharmony_ci		case ISCSI_PARAM_IFACE_NAME:
140762306a36Sopenharmony_ci		case ISCSI_PARAM_INITIATOR_NAME:
140862306a36Sopenharmony_ci			return S_IRUGO;
140962306a36Sopenharmony_ci		default:
141062306a36Sopenharmony_ci			return 0;
141162306a36Sopenharmony_ci		}
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	return 0;
141562306a36Sopenharmony_ci}
1416