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(¶ms, 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, ¶ms);929 beiscsi_offload_connection(beiscsi_conn, ¶ms);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