brintos

brintos / linux-shallow public Read only

0
0
Text · 38.1 KiB · 8d374ae Raw
1416 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI4 * Host Bus Adapters. Refer to the README file included with this package5 * for driver version and adapter compatibility.6 *7 * Copyright (c) 2018 Broadcom. All Rights Reserved.8 * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.9 *10 * Contact Information:11 * linux-drivers@broadcom.com12 */13 14#include <scsi/libiscsi.h>15#include <scsi/scsi_transport_iscsi.h>16#include <scsi/scsi_transport.h>17#include <scsi/scsi_cmnd.h>18#include <scsi/scsi_device.h>19#include <scsi/scsi_host.h>20#include <scsi/scsi_netlink.h>21#include <net/netlink.h>22#include <scsi/scsi.h>23 24#include "be_iscsi.h"25 26extern struct iscsi_transport beiscsi_iscsi_transport;27 28/**29 * beiscsi_session_create - creates a new iscsi session30 * @ep: pointer to iscsi ep31 * @cmds_max: max commands supported32 * @qdepth: max queue depth supported33 * @initial_cmdsn: initial iscsi CMDSN34 */35struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,36						 u16 cmds_max,37						 u16 qdepth,38						 u32 initial_cmdsn)39{40	struct Scsi_Host *shost;41	struct beiscsi_endpoint *beiscsi_ep;42	struct iscsi_cls_session *cls_session;43	struct beiscsi_hba *phba;44	struct iscsi_session *sess;45	struct beiscsi_session *beiscsi_sess;46	struct beiscsi_io_task *io_task;47 48 49	if (!ep) {50		pr_err("beiscsi_session_create: invalid ep\n");51		return NULL;52	}53	beiscsi_ep = ep->dd_data;54	phba = beiscsi_ep->phba;55 56	if (!beiscsi_hba_is_online(phba)) {57		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,58			    "BS_%d : HBA in error 0x%lx\n", phba->state);59		return NULL;60	}61 62	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,63		    "BS_%d : In beiscsi_session_create\n");64	if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {65		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,66			    "BS_%d : Cannot handle %d cmds."67			    "Max cmds per session supported is %d. Using %d."68			    "\n", cmds_max,69			    beiscsi_ep->phba->params.wrbs_per_cxn,70			    beiscsi_ep->phba->params.wrbs_per_cxn);71 72		cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;73	}74 75	shost = phba->shost;76	cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,77					  shost, cmds_max,78					  sizeof(*beiscsi_sess),79					  sizeof(*io_task),80					  initial_cmdsn, ISCSI_MAX_TARGET);81	if (!cls_session)82		return NULL;83	sess = cls_session->dd_data;84	beiscsi_sess = sess->dd_data;85	beiscsi_sess->bhs_pool =  dma_pool_create("beiscsi_bhs_pool",86						   &phba->pcidev->dev,87						   sizeof(struct be_cmd_bhs),88						   64, 0);89	if (!beiscsi_sess->bhs_pool)90		goto destroy_sess;91 92	return cls_session;93destroy_sess:94	iscsi_session_teardown(cls_session);95	return NULL;96}97 98/**99 * beiscsi_session_destroy - destroys iscsi session100 * @cls_session:	pointer to iscsi cls session101 *102 * Destroys iSCSI session instance and releases103 * resources allocated for it.104 */105void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)106{107	struct iscsi_session *sess = cls_session->dd_data;108	struct beiscsi_session *beiscsi_sess = sess->dd_data;109 110	printk(KERN_INFO "In beiscsi_session_destroy\n");111	dma_pool_destroy(beiscsi_sess->bhs_pool);112	iscsi_session_teardown(cls_session);113}114 115/**116 * beiscsi_session_fail(): Closing session with appropriate error117 * @cls_session: ptr to session118 **/119void beiscsi_session_fail(struct iscsi_cls_session *cls_session)120{121	iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);122}123 124 125/**126 * beiscsi_conn_create - create an instance of iscsi connection127 * @cls_session: ptr to iscsi_cls_session128 * @cid: iscsi cid129 */130struct iscsi_cls_conn *131beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)132{133	struct beiscsi_hba *phba;134	struct Scsi_Host *shost;135	struct iscsi_cls_conn *cls_conn;136	struct beiscsi_conn *beiscsi_conn;137	struct iscsi_conn *conn;138	struct iscsi_session *sess;139	struct beiscsi_session *beiscsi_sess;140 141	shost = iscsi_session_to_shost(cls_session);142	phba = iscsi_host_priv(shost);143 144	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,145		    "BS_%d : In beiscsi_conn_create ,cid"146		    "from iscsi layer=%d\n", cid);147 148	cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);149	if (!cls_conn)150		return NULL;151 152	conn = cls_conn->dd_data;153	beiscsi_conn = conn->dd_data;154	beiscsi_conn->ep = NULL;155	beiscsi_conn->phba = phba;156	beiscsi_conn->conn = conn;157	sess = cls_session->dd_data;158	beiscsi_sess = sess->dd_data;159	beiscsi_conn->beiscsi_sess = beiscsi_sess;160	return cls_conn;161}162 163/**164 * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection165 * @cls_session: pointer to iscsi cls session166 * @cls_conn: pointer to iscsi cls conn167 * @transport_fd: EP handle(64 bit)168 * @is_leading: indicate if this is the session leading connection (MCS)169 *170 * This function binds the TCP Conn with iSCSI Connection and Session.171 */172int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,173		      struct iscsi_cls_conn *cls_conn,174		      u64 transport_fd, int is_leading)175{176	struct iscsi_conn *conn = cls_conn->dd_data;177	struct beiscsi_conn *beiscsi_conn = conn->dd_data;178	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);179	struct beiscsi_hba *phba = iscsi_host_priv(shost);180	struct hwi_controller *phwi_ctrlr = phba->phwi_ctrlr;181	struct hwi_wrb_context *pwrb_context;182	struct beiscsi_endpoint *beiscsi_ep;183	struct iscsi_endpoint *ep;184	uint16_t cri_index;185	int rc = 0;186 187	ep = iscsi_lookup_endpoint(transport_fd);188	if (!ep)189		return -EINVAL;190 191	beiscsi_ep = ep->dd_data;192 193	if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {194		rc = -EINVAL;195		goto put_ep;196	}197 198	if (beiscsi_ep->phba != phba) {199		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,200			    "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",201			    beiscsi_ep->phba, phba);202		rc = -EEXIST;203		goto put_ep;204	}205	cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);206	if (phba->conn_table[cri_index]) {207		if (beiscsi_conn != phba->conn_table[cri_index] ||208		    beiscsi_ep != phba->conn_table[cri_index]->ep) {209			__beiscsi_log(phba, KERN_ERR,210				      "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n",211				      cri_index,212				      beiscsi_ep->ep_cid,213				      beiscsi_conn,214				      phba->conn_table[cri_index]);215			rc = -EINVAL;216			goto put_ep;217		}218	}219 220	beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;221	beiscsi_conn->ep = beiscsi_ep;222	beiscsi_ep->conn = beiscsi_conn;223	/**224	 * Each connection is associated with a WRBQ kept in wrb_context.225	 * Store doorbell offset for transmit path.226	 */227	pwrb_context = &phwi_ctrlr->wrb_context[cri_index];228	beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset;229	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,230		    "BS_%d : cid %d phba->conn_table[%u]=%p\n",231		    beiscsi_ep->ep_cid, cri_index, beiscsi_conn);232	phba->conn_table[cri_index] = beiscsi_conn;233 234put_ep:235	iscsi_put_endpoint(ep);236	return rc;237}238 239static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)240{241	if (phba->ipv4_iface)242		return 0;243 244	phba->ipv4_iface = iscsi_create_iface(phba->shost,245					      &beiscsi_iscsi_transport,246					      ISCSI_IFACE_TYPE_IPV4,247					      0, 0);248	if (!phba->ipv4_iface) {249		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,250			    "BS_%d : Could not "251			    "create default IPv4 address.\n");252		return -ENODEV;253	}254 255	return 0;256}257 258static int beiscsi_iface_create_ipv6(struct beiscsi_hba *phba)259{260	if (phba->ipv6_iface)261		return 0;262 263	phba->ipv6_iface = iscsi_create_iface(phba->shost,264					      &beiscsi_iscsi_transport,265					      ISCSI_IFACE_TYPE_IPV6,266					      0, 0);267	if (!phba->ipv6_iface) {268		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,269			    "BS_%d : Could not "270			    "create default IPv6 address.\n");271		return -ENODEV;272	}273 274	return 0;275}276 277void beiscsi_iface_create_default(struct beiscsi_hba *phba)278{279	struct be_cmd_get_if_info_resp *if_info;280 281	if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V4, &if_info)) {282		beiscsi_iface_create_ipv4(phba);283		kfree(if_info);284	}285 286	if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V6, &if_info)) {287		beiscsi_iface_create_ipv6(phba);288		kfree(if_info);289	}290}291 292void beiscsi_iface_destroy_default(struct beiscsi_hba *phba)293{294	if (phba->ipv6_iface) {295		iscsi_destroy_iface(phba->ipv6_iface);296		phba->ipv6_iface = NULL;297	}298	if (phba->ipv4_iface) {299		iscsi_destroy_iface(phba->ipv4_iface);300		phba->ipv4_iface = NULL;301	}302}303 304/**305 * beiscsi_iface_config_vlan()- Set the VLAN TAG306 * @shost: Scsi Host for the driver instance307 * @iface_param: Interface paramters308 *309 * Set the VLAN TAG for the adapter or disable310 * the VLAN config311 *312 * returns313 *	Success: 0314 *	Failure: Non-Zero Value315 **/316static int317beiscsi_iface_config_vlan(struct Scsi_Host *shost,318			  struct iscsi_iface_param_info *iface_param)319{320	struct beiscsi_hba *phba = iscsi_host_priv(shost);321	int ret = -EPERM;322 323	switch (iface_param->param) {324	case ISCSI_NET_PARAM_VLAN_ENABLED:325		ret = 0;326		if (iface_param->value[0] != ISCSI_VLAN_ENABLE)327			ret = beiscsi_if_set_vlan(phba, BEISCSI_VLAN_DISABLE);328		break;329	case ISCSI_NET_PARAM_VLAN_TAG:330		ret = beiscsi_if_set_vlan(phba,331					  *((uint16_t *)iface_param->value));332		break;333	}334	return ret;335}336 337 338static int339beiscsi_iface_config_ipv4(struct Scsi_Host *shost,340			  struct iscsi_iface_param_info *info,341			  void *data, uint32_t dt_len)342{343	struct beiscsi_hba *phba = iscsi_host_priv(shost);344	u8 *ip = NULL, *subnet = NULL, *gw;345	struct nlattr *nla;346	int ret = -EPERM;347 348	/* Check the param */349	switch (info->param) {350	case ISCSI_NET_PARAM_IFACE_ENABLE:351		if (info->value[0] == ISCSI_IFACE_ENABLE)352			ret = beiscsi_iface_create_ipv4(phba);353		else {354			iscsi_destroy_iface(phba->ipv4_iface);355			phba->ipv4_iface = NULL;356		}357		break;358	case ISCSI_NET_PARAM_IPV4_GW:359		gw = info->value;360		ret = beiscsi_if_set_gw(phba, BEISCSI_IP_TYPE_V4, gw);361		break;362	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:363		if (info->value[0] == ISCSI_BOOTPROTO_DHCP)364			ret = beiscsi_if_en_dhcp(phba, BEISCSI_IP_TYPE_V4);365		else if (info->value[0] == ISCSI_BOOTPROTO_STATIC)366			/* release DHCP IP address */367			ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,368						   NULL, NULL);369		else370			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,371				    "BS_%d : Invalid BOOTPROTO: %d\n",372				    info->value[0]);373		break;374	case ISCSI_NET_PARAM_IPV4_ADDR:375		ip = info->value;376		nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);377		if (nla) {378			info = nla_data(nla);379			subnet = info->value;380		}381		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,382					   ip, subnet);383		break;384	case ISCSI_NET_PARAM_IPV4_SUBNET:385		/*386		 * OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR ioctl needs IP387		 * and subnet both. Find IP to be applied for this subnet.388		 */389		subnet = info->value;390		nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);391		if (nla) {392			info = nla_data(nla);393			ip = info->value;394		}395		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,396					   ip, subnet);397		break;398	}399 400	return ret;401}402 403static int404beiscsi_iface_config_ipv6(struct Scsi_Host *shost,405			  struct iscsi_iface_param_info *iface_param,406			  void *data, uint32_t dt_len)407{408	struct beiscsi_hba *phba = iscsi_host_priv(shost);409	int ret = -EPERM;410 411	switch (iface_param->param) {412	case ISCSI_NET_PARAM_IFACE_ENABLE:413		if (iface_param->value[0] == ISCSI_IFACE_ENABLE)414			ret = beiscsi_iface_create_ipv6(phba);415		else {416			iscsi_destroy_iface(phba->ipv6_iface);417			phba->ipv6_iface = NULL;418		}419		break;420	case ISCSI_NET_PARAM_IPV6_ADDR:421		ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V6,422					   iface_param->value, NULL);423		break;424	}425 426	return ret;427}428 429int beiscsi_iface_set_param(struct Scsi_Host *shost,430			    void *data, uint32_t dt_len)431{432	struct iscsi_iface_param_info *iface_param = NULL;433	struct beiscsi_hba *phba = iscsi_host_priv(shost);434	struct nlattr *attrib;435	uint32_t rm_len = dt_len;436	int ret;437 438	if (!beiscsi_hba_is_online(phba)) {439		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,440			    "BS_%d : HBA in error 0x%lx\n", phba->state);441		return -EBUSY;442	}443 444	/* update interface_handle */445	ret = beiscsi_if_get_handle(phba);446	if (ret) {447		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,448			    "BS_%d : Getting Interface Handle Failed\n");449		return ret;450	}451 452	nla_for_each_attr(attrib, data, dt_len, rm_len) {453		/* ignore nla_type as it is never used */454		if (nla_len(attrib) < sizeof(*iface_param))455			return -EINVAL;456 457		iface_param = nla_data(attrib);458 459		if (iface_param->param_type != ISCSI_NET_PARAM)460			continue;461 462		/*463		 * BE2ISCSI only supports 1 interface464		 */465		if (iface_param->iface_num) {466			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,467				    "BS_%d : Invalid iface_num %d."468				    "Only iface_num 0 is supported.\n",469				    iface_param->iface_num);470 471			return -EINVAL;472		}473 474		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,475			    "BS_%d : %s.0 set param %d",476			    (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ?477			    "ipv4" : "ipv6", iface_param->param);478 479		ret = -EPERM;480		switch (iface_param->param) {481		case ISCSI_NET_PARAM_VLAN_ENABLED:482		case ISCSI_NET_PARAM_VLAN_TAG:483			ret = beiscsi_iface_config_vlan(shost, iface_param);484			break;485		default:486			switch (iface_param->iface_type) {487			case ISCSI_IFACE_TYPE_IPV4:488				ret = beiscsi_iface_config_ipv4(shost,489								iface_param,490								data, dt_len);491				break;492			case ISCSI_IFACE_TYPE_IPV6:493				ret = beiscsi_iface_config_ipv6(shost,494								iface_param,495								data, dt_len);496				break;497			}498		}499 500		if (ret == -EPERM) {501			__beiscsi_log(phba, KERN_ERR,502				      "BS_%d : %s.0 set param %d not permitted",503				      (iface_param->iface_type ==504				       ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6",505				      iface_param->param);506			ret = 0;507		}508		if (ret)509			break;510	}511 512	return ret;513}514 515static int __beiscsi_iface_get_param(struct beiscsi_hba *phba,516				     struct iscsi_iface *iface,517				     int param, char *buf)518{519	struct be_cmd_get_if_info_resp *if_info;520	int len, ip_type = BEISCSI_IP_TYPE_V4;521 522	if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)523		ip_type = BEISCSI_IP_TYPE_V6;524 525	len = beiscsi_if_get_info(phba, ip_type, &if_info);526	if (len)527		return len;528 529	switch (param) {530	case ISCSI_NET_PARAM_IPV4_ADDR:531		len = sprintf(buf, "%pI4\n", if_info->ip_addr.addr);532		break;533	case ISCSI_NET_PARAM_IPV6_ADDR:534		len = sprintf(buf, "%pI6\n", if_info->ip_addr.addr);535		break;536	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:537		if (!if_info->dhcp_state)538			len = sprintf(buf, "static\n");539		else540			len = sprintf(buf, "dhcp\n");541		break;542	case ISCSI_NET_PARAM_IPV4_SUBNET:543		len = sprintf(buf, "%pI4\n", if_info->ip_addr.subnet_mask);544		break;545	case ISCSI_NET_PARAM_VLAN_ENABLED:546		len = sprintf(buf, "%s\n",547			      (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) ?548			      "disable" : "enable");549		break;550	case ISCSI_NET_PARAM_VLAN_ID:551		if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)552			len = -EINVAL;553		else554			len = sprintf(buf, "%d\n",555				      (if_info->vlan_priority &556				       ISCSI_MAX_VLAN_ID));557		break;558	case ISCSI_NET_PARAM_VLAN_PRIORITY:559		if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)560			len = -EINVAL;561		else562			len = sprintf(buf, "%d\n",563				      ((if_info->vlan_priority >> 13) &564				       ISCSI_MAX_VLAN_PRIORITY));565		break;566	default:567		WARN_ON(1);568	}569 570	kfree(if_info);571	return len;572}573 574int beiscsi_iface_get_param(struct iscsi_iface *iface,575			    enum iscsi_param_type param_type,576			    int param, char *buf)577{578	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);579	struct beiscsi_hba *phba = iscsi_host_priv(shost);580	struct be_cmd_get_def_gateway_resp gateway;581	int len = -EPERM;582 583	if (param_type != ISCSI_NET_PARAM)584		return 0;585	if (!beiscsi_hba_is_online(phba)) {586		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,587			    "BS_%d : HBA in error 0x%lx\n", phba->state);588		return -EBUSY;589	}590 591	switch (param) {592	case ISCSI_NET_PARAM_IPV4_ADDR:593	case ISCSI_NET_PARAM_IPV4_SUBNET:594	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:595	case ISCSI_NET_PARAM_IPV6_ADDR:596	case ISCSI_NET_PARAM_VLAN_ENABLED:597	case ISCSI_NET_PARAM_VLAN_ID:598	case ISCSI_NET_PARAM_VLAN_PRIORITY:599		len = __beiscsi_iface_get_param(phba, iface, param, buf);600		break;601	case ISCSI_NET_PARAM_IFACE_ENABLE:602		if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)603			len = sprintf(buf, "%s\n",604				      phba->ipv4_iface ? "enable" : "disable");605		else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)606			len = sprintf(buf, "%s\n",607				      phba->ipv6_iface ? "enable" : "disable");608		break;609	case ISCSI_NET_PARAM_IPV4_GW:610		memset(&gateway, 0, sizeof(gateway));611		len = beiscsi_if_get_gw(phba, BEISCSI_IP_TYPE_V4, &gateway);612		if (!len)613			len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr);614		break;615	}616 617	return len;618}619 620/**621 * beiscsi_ep_get_param - get the iscsi parameter622 * @ep: pointer to iscsi ep623 * @param: parameter type identifier624 * @buf: buffer pointer625 *626 * returns iscsi parameter627 */628int beiscsi_ep_get_param(struct iscsi_endpoint *ep,629			   enum iscsi_param param, char *buf)630{631	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;632	int len;633 634	beiscsi_log(beiscsi_ep->phba, KERN_INFO,635		    BEISCSI_LOG_CONFIG,636		    "BS_%d : In beiscsi_ep_get_param,"637		    " param= %d\n", param);638 639	switch (param) {640	case ISCSI_PARAM_CONN_PORT:641		len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);642		break;643	case ISCSI_PARAM_CONN_ADDRESS:644		if (beiscsi_ep->ip_type == BEISCSI_IP_TYPE_V4)645			len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);646		else647			len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);648		break;649	default:650		len = -EPERM;651	}652	return len;653}654 655int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,656		      enum iscsi_param param, char *buf, int buflen)657{658	struct iscsi_conn *conn = cls_conn->dd_data;659	struct iscsi_session *session = conn->session;660	struct beiscsi_hba *phba = NULL;661	int ret;662 663	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;664	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,665		    "BS_%d : In beiscsi_conn_set_param,"666		    " param= %d\n", param);667 668	ret = iscsi_set_param(cls_conn, param, buf, buflen);669	if (ret)670		return ret;671	/*672	 * If userspace tried to set the value to higher than we can673	 * support override here.674	 */675	switch (param) {676	case ISCSI_PARAM_FIRST_BURST:677		if (session->first_burst > 8192)678			session->first_burst = 8192;679		break;680	case ISCSI_PARAM_MAX_RECV_DLENGTH:681		if (conn->max_recv_dlength > 65536)682			conn->max_recv_dlength = 65536;683		break;684	case ISCSI_PARAM_MAX_BURST:685		if (session->max_burst > 262144)686			session->max_burst = 262144;687		break;688	case ISCSI_PARAM_MAX_XMIT_DLENGTH:689		if (conn->max_xmit_dlength > 65536)690			conn->max_xmit_dlength = 65536;691		fallthrough;692	default:693		return 0;694	}695 696	return 0;697}698 699/**700 * beiscsi_get_port_state - Get the Port State701 * @shost : pointer to scsi_host structure702 *703 */704static void beiscsi_get_port_state(struct Scsi_Host *shost)705{706	struct beiscsi_hba *phba = iscsi_host_priv(shost);707	struct iscsi_cls_host *ihost = shost->shost_data;708 709	ihost->port_state = test_bit(BEISCSI_HBA_LINK_UP, &phba->state) ?710		ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;711}712 713/**714 * beiscsi_get_port_speed  - Get the Port Speed from Adapter715 * @shost : pointer to scsi_host structure716 *717 */718static void beiscsi_get_port_speed(struct Scsi_Host *shost)719{720	struct beiscsi_hba *phba = iscsi_host_priv(shost);721	struct iscsi_cls_host *ihost = shost->shost_data;722 723	switch (phba->port_speed) {724	case BE2ISCSI_LINK_SPEED_10MBPS:725		ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;726		break;727	case BE2ISCSI_LINK_SPEED_100MBPS:728		ihost->port_speed = ISCSI_PORT_SPEED_100MBPS;729		break;730	case BE2ISCSI_LINK_SPEED_1GBPS:731		ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;732		break;733	case BE2ISCSI_LINK_SPEED_10GBPS:734		ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;735		break;736	case BE2ISCSI_LINK_SPEED_25GBPS:737		ihost->port_speed = ISCSI_PORT_SPEED_25GBPS;738		break;739	case BE2ISCSI_LINK_SPEED_40GBPS:740		ihost->port_speed = ISCSI_PORT_SPEED_40GBPS;741		break;742	default:743		ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;744	}745}746 747/**748 * beiscsi_get_host_param - get the iscsi parameter749 * @shost: pointer to scsi_host structure750 * @param: parameter type identifier751 * @buf: buffer pointer752 *753 */754int beiscsi_get_host_param(struct Scsi_Host *shost,755			   enum iscsi_host_param param, char *buf)756{757	struct beiscsi_hba *phba = iscsi_host_priv(shost);758	int status = 0;759 760	if (!beiscsi_hba_is_online(phba)) {761		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,762			    "BS_%d : HBA in error 0x%lx\n", phba->state);763		return 0;764	}765	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,766		    "BS_%d : In beiscsi_get_host_param, param = %d\n", param);767 768	switch (param) {769	case ISCSI_HOST_PARAM_HWADDRESS:770		status = beiscsi_get_macaddr(buf, phba);771		if (status < 0) {772			beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,773				    "BS_%d : beiscsi_get_macaddr Failed\n");774			return 0;775		}776		break;777	case ISCSI_HOST_PARAM_INITIATOR_NAME:778		/* try fetching user configured name first */779		status = beiscsi_get_initiator_name(phba, buf, true);780		if (status < 0) {781			status = beiscsi_get_initiator_name(phba, buf, false);782			if (status < 0) {783				beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,784					    "BS_%d : Retrieving Initiator Name Failed\n");785				status = 0;786			}787		}788		break;789	case ISCSI_HOST_PARAM_PORT_STATE:790		beiscsi_get_port_state(shost);791		status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));792		break;793	case ISCSI_HOST_PARAM_PORT_SPEED:794		beiscsi_get_port_speed(shost);795		status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));796		break;797	default:798		return iscsi_host_get_param(shost, param, buf);799	}800	return status;801}802 803int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)804{805	struct be_cmd_get_nic_conf_resp resp;806	int rc;807 808	if (phba->mac_addr_set)809		return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);810 811	memset(&resp, 0, sizeof(resp));812	rc = mgmt_get_nic_conf(phba, &resp);813	if (rc)814		return rc;815 816	phba->mac_addr_set = true;817	memcpy(phba->mac_address, resp.mac_address, ETH_ALEN);818	return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);819}820 821/**822 * beiscsi_conn_get_stats - get the iscsi stats823 * @cls_conn: pointer to iscsi cls conn824 * @stats: pointer to iscsi_stats structure825 *826 * returns iscsi stats827 */828void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,829			    struct iscsi_stats *stats)830{831	struct iscsi_conn *conn = cls_conn->dd_data;832	struct beiscsi_hba *phba = NULL;833 834	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;835	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,836		    "BS_%d : In beiscsi_conn_get_stats\n");837 838	stats->txdata_octets = conn->txdata_octets;839	stats->rxdata_octets = conn->rxdata_octets;840	stats->dataout_pdus = conn->dataout_pdus_cnt;841	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;842	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;843	stats->datain_pdus = conn->datain_pdus_cnt;844	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;845	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;846	stats->r2t_pdus = conn->r2t_pdus_cnt;847	stats->digest_err = 0;848	stats->timeout_err = 0;849	stats->custom_length = 1;850	strcpy(stats->custom[0].desc, "eh_abort_cnt");851	stats->custom[0].value = conn->eh_abort_cnt;852}853 854/**855 * beiscsi_set_params_for_offld - get the parameters for offload856 * @beiscsi_conn: pointer to beiscsi_conn857 * @params: pointer to offload_params structure858 */859static void  beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,860					  struct beiscsi_offload_params *params)861{862	struct iscsi_conn *conn = beiscsi_conn->conn;863	struct iscsi_session *session = conn->session;864 865	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,866		      params, session->max_burst);867	AMAP_SET_BITS(struct amap_beiscsi_offload_params,868		      max_send_data_segment_length, params,869		      conn->max_xmit_dlength);870	AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,871		      params, session->first_burst);872	AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,873		      session->erl);874	AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,875		      conn->datadgst_en);876	AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,877		      conn->hdrdgst_en);878	AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,879		      session->initial_r2t_en);880	AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,881		      session->imm_data_en);882	AMAP_SET_BITS(struct amap_beiscsi_offload_params,883		      data_seq_inorder, params,884		      session->dataseq_inorder_en);885	AMAP_SET_BITS(struct amap_beiscsi_offload_params,886		      pdu_seq_inorder, params,887		      session->pdu_inorder_en);888	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_r2t, params,889		      session->max_r2t);890	AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,891		      (conn->exp_statsn - 1));892	AMAP_SET_BITS(struct amap_beiscsi_offload_params,893		      max_recv_data_segment_length, params,894		      conn->max_recv_dlength);895 896}897 898/**899 * beiscsi_conn_start - offload of session to chip900 * @cls_conn: pointer to beiscsi_conn901 */902int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)903{904	struct iscsi_conn *conn = cls_conn->dd_data;905	struct beiscsi_conn *beiscsi_conn = conn->dd_data;906	struct beiscsi_endpoint *beiscsi_ep;907	struct beiscsi_offload_params params;908	struct beiscsi_hba *phba;909 910	phba = ((struct beiscsi_conn *)conn->dd_data)->phba;911 912	if (!beiscsi_hba_is_online(phba)) {913		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,914			    "BS_%d : HBA in error 0x%lx\n", phba->state);915		return -EBUSY;916	}917	beiscsi_log(beiscsi_conn->phba, KERN_INFO, BEISCSI_LOG_CONFIG,918		    "BS_%d : In beiscsi_conn_start\n");919 920	memset(&params, 0, sizeof(struct beiscsi_offload_params));921	beiscsi_ep = beiscsi_conn->ep;922	if (!beiscsi_ep)923		beiscsi_log(beiscsi_conn->phba, KERN_ERR,924			    BEISCSI_LOG_CONFIG,925			    "BS_%d : In beiscsi_conn_start , no beiscsi_ep\n");926 927	beiscsi_conn->login_in_progress = 0;928	beiscsi_set_params_for_offld(beiscsi_conn, &params);929	beiscsi_offload_connection(beiscsi_conn, &params);930	iscsi_conn_start(cls_conn);931	return 0;932}933 934/**935 * beiscsi_get_cid - Allocate a cid936 * @phba: The phba instance937 */938static int beiscsi_get_cid(struct beiscsi_hba *phba)939{940	uint16_t cid_avlbl_ulp0, cid_avlbl_ulp1;941	unsigned short cid, cid_from_ulp;942	struct ulp_cid_info *cid_info;943 944	/* Find the ULP which has more CID available */945	cid_avlbl_ulp0 = (phba->cid_array_info[BEISCSI_ULP0]) ?946			  BEISCSI_ULP0_AVLBL_CID(phba) : 0;947	cid_avlbl_ulp1 = (phba->cid_array_info[BEISCSI_ULP1]) ?948			  BEISCSI_ULP1_AVLBL_CID(phba) : 0;949	cid_from_ulp = (cid_avlbl_ulp0 > cid_avlbl_ulp1) ?950			BEISCSI_ULP0 : BEISCSI_ULP1;951	/**952	 * If iSCSI protocol is loaded only on ULP 0, and when cid_avlbl_ulp953	 * is ZERO for both, ULP 1 is returned.954	 * Check if ULP is loaded before getting new CID.955	 */956	if (!test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported))957		return BE_INVALID_CID;958 959	cid_info = phba->cid_array_info[cid_from_ulp];960	cid = cid_info->cid_array[cid_info->cid_alloc];961	if (!cid_info->avlbl_cids || cid == BE_INVALID_CID) {962		__beiscsi_log(phba, KERN_ERR,963				"BS_%d : failed to get cid: available %u:%u\n",964				cid_info->avlbl_cids, cid_info->cid_free);965		return BE_INVALID_CID;966	}967	/* empty the slot */968	cid_info->cid_array[cid_info->cid_alloc++] = BE_INVALID_CID;969	if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(phba, cid_from_ulp))970		cid_info->cid_alloc = 0;971	cid_info->avlbl_cids--;972	return cid;973}974 975/**976 * beiscsi_put_cid - Free the cid977 * @phba: The phba for which the cid is being freed978 * @cid: The cid to free979 */980static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)981{982	uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);983	struct hwi_wrb_context *pwrb_context;984	struct hwi_controller *phwi_ctrlr;985	struct ulp_cid_info *cid_info;986	uint16_t cid_post_ulp;987 988	phwi_ctrlr = phba->phwi_ctrlr;989	pwrb_context = &phwi_ctrlr->wrb_context[cri_index];990	cid_post_ulp = pwrb_context->ulp_num;991 992	cid_info = phba->cid_array_info[cid_post_ulp];993	/* fill only in empty slot */994	if (cid_info->cid_array[cid_info->cid_free] != BE_INVALID_CID) {995		__beiscsi_log(phba, KERN_ERR,996			      "BS_%d : failed to put cid %u: available %u:%u\n",997			      cid, cid_info->avlbl_cids, cid_info->cid_free);998		return;999	}1000	cid_info->cid_array[cid_info->cid_free++] = cid;1001	if (cid_info->cid_free == BEISCSI_GET_CID_COUNT(phba, cid_post_ulp))1002		cid_info->cid_free = 0;1003	cid_info->avlbl_cids++;1004}1005 1006/**1007 * beiscsi_free_ep - free endpoint1008 * @beiscsi_ep: pointer to device endpoint struct1009 */1010static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)1011{1012	struct beiscsi_hba *phba = beiscsi_ep->phba;1013	struct beiscsi_conn *beiscsi_conn;1014 1015	beiscsi_put_cid(phba, beiscsi_ep->ep_cid);1016	beiscsi_ep->phba = NULL;1017	/* clear this to track freeing in beiscsi_ep_disconnect */1018	phba->ep_array[BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid)] = NULL;1019 1020	/**1021	 * Check if any connection resource allocated by driver1022	 * is to be freed.This case occurs when target redirection1023	 * or connection retry is done.1024	 **/1025	if (!beiscsi_ep->conn)1026		return;1027 1028	beiscsi_conn = beiscsi_ep->conn;1029	/**1030	 * Break ep->conn link here so that completions after1031	 * this are ignored.1032	 */1033	beiscsi_ep->conn = NULL;1034	if (beiscsi_conn->login_in_progress) {1035		beiscsi_free_mgmt_task_handles(beiscsi_conn,1036					       beiscsi_conn->task);1037		beiscsi_conn->login_in_progress = 0;1038	}1039}1040 1041/**1042 * beiscsi_open_conn - Ask FW to open a TCP connection1043 * @ep: pointer to device endpoint struct1044 * @src_addr: The source IP address1045 * @dst_addr: The Destination  IP address1046 * @non_blocking: blocking or non-blocking call1047 *1048 * Asks the FW to open a TCP connection1049 */1050static int beiscsi_open_conn(struct iscsi_endpoint *ep,1051			     struct sockaddr *src_addr,1052			     struct sockaddr *dst_addr, int non_blocking)1053{1054	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;1055	struct beiscsi_hba *phba = beiscsi_ep->phba;1056	struct tcp_connect_and_offload_out *ptcpcnct_out;1057	struct be_dma_mem nonemb_cmd;1058	unsigned int tag, req_memsize;1059	int ret = -ENOMEM;1060 1061	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1062		    "BS_%d : In beiscsi_open_conn\n");1063 1064	beiscsi_ep->ep_cid = beiscsi_get_cid(phba);1065	if (beiscsi_ep->ep_cid == BE_INVALID_CID) {1066		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,1067			    "BS_%d : No free cid available\n");1068		return ret;1069	}1070 1071	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1072		    "BS_%d : In beiscsi_open_conn, ep_cid=%d\n",1073		    beiscsi_ep->ep_cid);1074 1075	phba->ep_array[BE_GET_CRI_FROM_CID1076		       (beiscsi_ep->ep_cid)] = ep;1077 1078	beiscsi_ep->cid_vld = 0;1079 1080	if (is_chip_be2_be3r(phba))1081		req_memsize = sizeof(struct tcp_connect_and_offload_in);1082	else1083		req_memsize = sizeof(struct tcp_connect_and_offload_in_v1);1084 1085	nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev,1086				req_memsize,1087				&nonemb_cmd.dma, GFP_KERNEL);1088	if (nonemb_cmd.va == NULL) {1089 1090		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,1091			    "BS_%d : Failed to allocate memory for"1092			    " mgmt_open_connection\n");1093 1094		beiscsi_free_ep(beiscsi_ep);1095		return -ENOMEM;1096	}1097	nonemb_cmd.size = req_memsize;1098	memset(nonemb_cmd.va, 0, nonemb_cmd.size);1099	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);1100	if (!tag) {1101		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,1102			    "BS_%d : mgmt_open_connection Failed for cid=%d\n",1103			    beiscsi_ep->ep_cid);1104 1105		dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,1106				    nonemb_cmd.va, nonemb_cmd.dma);1107		beiscsi_free_ep(beiscsi_ep);1108		return -EAGAIN;1109	}1110 1111	ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);1112	if (ret) {1113		beiscsi_log(phba, KERN_ERR,1114			    BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,1115			    "BS_%d : mgmt_open_connection Failed");1116 1117		if (ret != -EBUSY)1118			dma_free_coherent(&phba->ctrl.pdev->dev,1119					nonemb_cmd.size, nonemb_cmd.va,1120					nonemb_cmd.dma);1121 1122		beiscsi_free_ep(beiscsi_ep);1123		return ret;1124	}1125 1126	ptcpcnct_out = (struct tcp_connect_and_offload_out *)nonemb_cmd.va;1127	beiscsi_ep = ep->dd_data;1128	beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;1129	beiscsi_ep->cid_vld = 1;1130	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1131		    "BS_%d : mgmt_open_connection Success\n");1132 1133	dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,1134			    nonemb_cmd.va, nonemb_cmd.dma);1135	return 0;1136}1137 1138/**1139 * beiscsi_ep_connect - Ask chip to create TCP Conn1140 * @shost: Pointer to scsi_host structure1141 * @dst_addr: The IP address of Target1142 * @non_blocking: blocking or non-blocking call1143 *1144 * This routines first asks chip to create a connection and then allocates an EP1145 */1146struct iscsi_endpoint *1147beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,1148		   int non_blocking)1149{1150	struct beiscsi_hba *phba;1151	struct beiscsi_endpoint *beiscsi_ep;1152	struct iscsi_endpoint *ep;1153	int ret;1154 1155	if (!shost) {1156		ret = -ENXIO;1157		pr_err("beiscsi_ep_connect shost is NULL\n");1158		return ERR_PTR(ret);1159	}1160 1161	phba = iscsi_host_priv(shost);1162	if (!beiscsi_hba_is_online(phba)) {1163		ret = -EIO;1164		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1165			    "BS_%d : HBA in error 0x%lx\n", phba->state);1166		return ERR_PTR(ret);1167	}1168	if (!test_bit(BEISCSI_HBA_LINK_UP, &phba->state)) {1169		ret = -EBUSY;1170		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,1171			    "BS_%d : The Adapter Port state is Down!!!\n");1172		return ERR_PTR(ret);1173	}1174 1175	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));1176	if (!ep) {1177		ret = -ENOMEM;1178		return ERR_PTR(ret);1179	}1180 1181	beiscsi_ep = ep->dd_data;1182	beiscsi_ep->phba = phba;1183	beiscsi_ep->openiscsi_ep = ep;1184	ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking);1185	if (ret) {1186		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,1187			    "BS_%d : Failed in beiscsi_open_conn\n");1188		goto free_ep;1189	}1190 1191	return ep;1192 1193free_ep:1194	iscsi_destroy_endpoint(ep);1195	return ERR_PTR(ret);1196}1197 1198/**1199 * beiscsi_ep_poll - Poll to see if connection is established1200 * @ep:	endpoint to be used1201 * @timeout_ms: timeout specified in millisecs1202 *1203 * Poll to see if TCP connection established1204 */1205int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)1206{1207	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;1208 1209	beiscsi_log(beiscsi_ep->phba, KERN_INFO, BEISCSI_LOG_CONFIG,1210		    "BS_%d : In  beiscsi_ep_poll\n");1211 1212	if (beiscsi_ep->cid_vld == 1)1213		return 1;1214	else1215		return 0;1216}1217 1218/**1219 * beiscsi_flush_cq()- Flush the CQ created.1220 * @phba: ptr device priv structure.1221 *1222 * Before the connection resource are freed flush1223 * all the CQ enteries1224 **/1225static void beiscsi_flush_cq(struct beiscsi_hba *phba)1226{1227	uint16_t i;1228	struct be_eq_obj *pbe_eq;1229	struct hwi_controller *phwi_ctrlr;1230	struct hwi_context_memory *phwi_context;1231 1232	phwi_ctrlr = phba->phwi_ctrlr;1233	phwi_context = phwi_ctrlr->phwi_ctxt;1234 1235	for (i = 0; i < phba->num_cpus; i++) {1236		pbe_eq = &phwi_context->be_eq[i];1237		irq_poll_disable(&pbe_eq->iopoll);1238		beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);1239		irq_poll_enable(&pbe_eq->iopoll);1240	}1241}1242 1243/**1244 * beiscsi_conn_close - Invalidate and upload connection1245 * @beiscsi_ep: pointer to device endpoint struct1246 *1247 * Returns 0 on success,  -1 on failure.1248 */1249static int beiscsi_conn_close(struct beiscsi_endpoint *beiscsi_ep)1250{1251	struct beiscsi_hba *phba = beiscsi_ep->phba;1252	unsigned int tag, attempts;1253	int ret;1254 1255	/**1256	 * Without successfully invalidating and uploading connection1257	 * driver can't reuse the CID so attempt more than once.1258	 */1259	attempts = 0;1260	while (attempts++ < 3) {1261		tag = beiscsi_invalidate_cxn(phba, beiscsi_ep);1262		if (tag) {1263			ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);1264			if (!ret)1265				break;1266			beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1267				    "BS_%d : invalidate conn failed cid %d\n",1268				    beiscsi_ep->ep_cid);1269		}1270	}1271 1272	/* wait for all completions to arrive, then process them */1273	msleep(250);1274	/* flush CQ entries */1275	beiscsi_flush_cq(phba);1276 1277	if (attempts > 3)1278		return -1;1279 1280	attempts = 0;1281	while (attempts++ < 3) {1282		tag = beiscsi_upload_cxn(phba, beiscsi_ep);1283		if (tag) {1284			ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);1285			if (!ret)1286				break;1287			beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1288				    "BS_%d : upload conn failed cid %d\n",1289				    beiscsi_ep->ep_cid);1290		}1291	}1292	if (attempts > 3)1293		return -1;1294 1295	return 0;1296}1297 1298/**1299 * beiscsi_ep_disconnect - Tears down the TCP connection1300 * @ep:	endpoint to be used1301 *1302 * Tears down the TCP connection1303 */1304void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)1305{1306	struct beiscsi_endpoint *beiscsi_ep;1307	struct beiscsi_hba *phba;1308	uint16_t cri_index;1309 1310	beiscsi_ep = ep->dd_data;1311	phba = beiscsi_ep->phba;1312	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1313		    "BS_%d : In beiscsi_ep_disconnect for ep_cid = %u\n",1314		    beiscsi_ep->ep_cid);1315 1316	cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);1317	if (!phba->ep_array[cri_index]) {1318		__beiscsi_log(phba, KERN_ERR,1319			      "BS_%d : ep_array at %u cid %u empty\n",1320			      cri_index,1321			      beiscsi_ep->ep_cid);1322		return;1323	}1324 1325	if (!beiscsi_hba_is_online(phba)) {1326		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,1327			    "BS_%d : HBA in error 0x%lx\n", phba->state);1328	} else {1329		/**1330		 * Make CID available even if close fails.1331		 * If not freed, FW might fail open using the CID.1332		 */1333		if (beiscsi_conn_close(beiscsi_ep) < 0)1334			__beiscsi_log(phba, KERN_ERR,1335				      "BS_%d : close conn failed cid %d\n",1336				      beiscsi_ep->ep_cid);1337	}1338 1339	beiscsi_free_ep(beiscsi_ep);1340	if (!phba->conn_table[cri_index])1341		__beiscsi_log(phba, KERN_ERR,1342			      "BS_%d : conn_table empty at %u: cid %u\n",1343			      cri_index, beiscsi_ep->ep_cid);1344	phba->conn_table[cri_index] = NULL;1345	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);1346}1347 1348umode_t beiscsi_attr_is_visible(int param_type, int param)1349{1350	switch (param_type) {1351	case ISCSI_NET_PARAM:1352		switch (param) {1353		case ISCSI_NET_PARAM_IFACE_ENABLE:1354		case ISCSI_NET_PARAM_IPV4_ADDR:1355		case ISCSI_NET_PARAM_IPV4_SUBNET:1356		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:1357		case ISCSI_NET_PARAM_IPV4_GW:1358		case ISCSI_NET_PARAM_IPV6_ADDR:1359		case ISCSI_NET_PARAM_VLAN_ID:1360		case ISCSI_NET_PARAM_VLAN_PRIORITY:1361		case ISCSI_NET_PARAM_VLAN_ENABLED:1362			return S_IRUGO;1363		default:1364			return 0;1365		}1366	case ISCSI_HOST_PARAM:1367		switch (param) {1368		case ISCSI_HOST_PARAM_HWADDRESS:1369		case ISCSI_HOST_PARAM_INITIATOR_NAME:1370		case ISCSI_HOST_PARAM_PORT_STATE:1371		case ISCSI_HOST_PARAM_PORT_SPEED:1372			return S_IRUGO;1373		default:1374			return 0;1375		}1376	case ISCSI_PARAM:1377		switch (param) {1378		case ISCSI_PARAM_MAX_RECV_DLENGTH:1379		case ISCSI_PARAM_MAX_XMIT_DLENGTH:1380		case ISCSI_PARAM_HDRDGST_EN:1381		case ISCSI_PARAM_DATADGST_EN:1382		case ISCSI_PARAM_CONN_ADDRESS:1383		case ISCSI_PARAM_CONN_PORT:1384		case ISCSI_PARAM_EXP_STATSN:1385		case ISCSI_PARAM_PERSISTENT_ADDRESS:1386		case ISCSI_PARAM_PERSISTENT_PORT:1387		case ISCSI_PARAM_PING_TMO:1388		case ISCSI_PARAM_RECV_TMO:1389		case ISCSI_PARAM_INITIAL_R2T_EN:1390		case ISCSI_PARAM_MAX_R2T:1391		case ISCSI_PARAM_IMM_DATA_EN:1392		case ISCSI_PARAM_FIRST_BURST:1393		case ISCSI_PARAM_MAX_BURST:1394		case ISCSI_PARAM_PDU_INORDER_EN:1395		case ISCSI_PARAM_DATASEQ_INORDER_EN:1396		case ISCSI_PARAM_ERL:1397		case ISCSI_PARAM_TARGET_NAME:1398		case ISCSI_PARAM_TPGT:1399		case ISCSI_PARAM_USERNAME:1400		case ISCSI_PARAM_PASSWORD:1401		case ISCSI_PARAM_USERNAME_IN:1402		case ISCSI_PARAM_PASSWORD_IN:1403		case ISCSI_PARAM_FAST_ABORT:1404		case ISCSI_PARAM_ABORT_TMO:1405		case ISCSI_PARAM_LU_RESET_TMO:1406		case ISCSI_PARAM_IFACE_NAME:1407		case ISCSI_PARAM_INITIATOR_NAME:1408			return S_IRUGO;1409		default:1410			return 0;1411		}1412	}1413 1414	return 0;1415}1416