aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas8
-rw-r--r--MAINTAINERS9
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/aacraid/src.c2
-rw-r--r--drivers/scsi/be2iscsi/be.h4
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c2
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h154
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c493
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h15
-rw-r--r--drivers/scsi/be2iscsi/be_main.c447
-rw-r--r--drivers/scsi/be2iscsi/be_main.h17
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c522
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h50
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h3
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c32
-rw-r--r--drivers/scsi/bfa/bfad.c17
-rw-r--r--drivers/scsi/bfa/bfad_attr.c20
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h2
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_hsi.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c6
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c3
-rw-r--r--drivers/scsi/bnx2i/bnx2i_sysfs.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c70
-rw-r--r--drivers/scsi/fcoe/fcoe.c41
-rw-r--r--drivers/scsi/fcoe/fcoe.h4
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c8
-rw-r--r--drivers/scsi/hpsa.c683
-rw-r--r--drivers/scsi/hpsa.h85
-rw-r--r--drivers/scsi/hpsa_cmd.h37
-rw-r--r--drivers/scsi/libfc/fc_lport.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c46
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h418
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c141
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c18
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c377
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c9
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c414
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c785
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c21
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c4
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h68
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c38
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h10
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c312
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c597
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c243
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h3
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c23
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c10
-rw-r--r--drivers/scsi/scsi.c6
-rw-r--r--drivers/scsi/scsi_lib.c10
-rw-r--r--drivers/scsi/scsi_pm.c2
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_transport_fc.c24
-rw-r--r--drivers/scsi/scsi_transport_spi.c4
-rw-r--r--drivers/scsi/sd.c5
-rw-r--r--drivers/scsi/sg.c183
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/storvsc_drv.c20
-rw-r--r--drivers/scsi/ufs/ufshcd.c8
-rw-r--r--include/scsi/iscsi_proto.h2
76 files changed, 4626 insertions, 2002 deletions
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 83f8ea8b79e..80441ab608e 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,11 @@
+Release Date : Mon. Mar 19, 2012 17:00:00 PST 2012 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+Current Version : 00.00.06.15-rc1
+Old Version : 00.00.06.14-rc1
+ 1. Optimize HostMSIxVectors setting.
+ 2. Add fpRead/WriteCapable, fpRead/WriteAcrossStripe checks.
+-------------------------------------------------------------------------------
Release Date : Fri. Jan 6, 2012 17:00:00 PST 2010 -
(emaild-id:megaraidlinux@lsi.com)
Adam Radford
diff --git a/MAINTAINERS b/MAINTAINERS
index b3627098650..87952045213 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1598,6 +1598,7 @@ F: include/linux/bcma/
BROCADE BFA FC SCSI DRIVER
M: Jing Huang <huangj@brocade.com>
+M: Krishna C Gudipati <kgudipat@brocade.com>
L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bfa/
@@ -6883,6 +6884,14 @@ F: Documentation/cdrom/
F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
+UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
+M: Vinayak Holikatti <vinholikatti@gmail.com>
+M: Santosh Y <santoshsy@gmail.com>
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: Documentation/scsi/ufs.txt
+F: drivers/scsi/ufs/
+
UNSORTED BLOCK IMAGES (UBI)
M: Artem Bityutskiy <dedekind1@gmail.com>
W: http://www.linux-mtd.infradead.org/
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 29684c8142b..bea04e5d3b5 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -408,6 +408,7 @@ config BLK_DEV_3W_XXXX_RAID
config SCSI_HPSA
tristate "HP Smart Array SCSI driver"
depends on PCI && SCSI
+ select CHECK_SIGNATURE
help
This driver supports HP Smart Array Controllers (circa 2009).
It is a SCSI alternative to the cciss driver, which is a block
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 2bee51506a9..76282063630 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -424,6 +424,8 @@ static int aac_src_deliver_message(struct fib *fib)
static int aac_src_ioremap(struct aac_dev *dev, u32 size)
{
if (!size) {
+ iounmap(dev->regs.src.bar1);
+ dev->regs.src.bar1 = NULL;
iounmap(dev->regs.src.bar0);
dev->base = dev->regs.src.bar0 = NULL;
return 0;
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 1d7b976c850..a50b6a9030e 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -132,10 +132,6 @@ struct be_ctrl_info {
((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
-/* Byte offset into the page corresponding to given address */
-#define OFFSET_IN_PAGE(addr) \
- ((size_t)(addr) & (PAGE_SIZE_4K-1))
-
/* Returns bit offset within a DWORD of a bitfield */
#define AMAP_BIT_OFFSET(_struct, field) \
(((size_t)&(((_struct *)0)->field))%32)
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index cdb15364bc6..d2e9e933f7a 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -15,6 +15,8 @@
* Costa Mesa, CA 92626
*/
+#include <scsi/iscsi_proto.h>
+
#include "be.h"
#include "be_mgmt.h"
#include "be_main.h"
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 8b40a5b4366..b0b36c6a145 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -23,7 +23,7 @@
* firmware in the BE. These requests are communicated to the processor
* using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one
* WRB inside a MAILBOX.
- * The commands are serviced by the ARM processor in the BladeEngine's MPU.
+ * The commands are serviced by the ARM processor in the OneConnect's MPU.
*/
struct be_sge {
u32 pa_lo;
@@ -163,7 +163,8 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3
#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7
#define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14
-#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17
+#define OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR 17
+#define OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR 18
#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21
#define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22
#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23
@@ -274,15 +275,15 @@ struct mgmt_conn_login_options {
struct mgmt_auth_method_format auth_data;
} __packed;
-struct ip_address_format {
+struct ip_addr_format {
u16 size_of_structure;
u8 reserved;
u8 ip_type;
- u8 ip_address[16];
+ u8 addr[16];
u32 rsvd0;
} __packed;
-struct mgmt_conn_info {
+struct mgmt_conn_info {
u32 connection_handle;
u32 connection_status;
u16 src_port;
@@ -290,9 +291,9 @@ struct mgmt_conn_info {
u16 dest_port_redirected;
u16 cid;
u32 estimated_throughput;
- struct ip_address_format src_ipaddr;
- struct ip_address_format dest_ipaddr;
- struct ip_address_format dest_ipaddr_redirected;
+ struct ip_addr_format src_ipaddr;
+ struct ip_addr_format dest_ipaddr;
+ struct ip_addr_format dest_ipaddr_redirected;
struct mgmt_conn_login_options negotiated_login_options;
} __packed;
@@ -322,43 +323,115 @@ struct mgmt_session_info {
struct mgmt_conn_info conn_list[1];
} __packed;
-struct be_cmd_req_get_session {
+struct be_cmd_get_session_req {
struct be_cmd_req_hdr hdr;
u32 session_handle;
} __packed;
-struct be_cmd_resp_get_session {
+struct be_cmd_get_session_resp {
struct be_cmd_resp_hdr hdr;
struct mgmt_session_info session_info;
} __packed;
struct mac_addr {
- u16 size_of_struct;
+ u16 size_of_structure;
u8 addr[ETH_ALEN];
} __packed;
-struct be_cmd_req_get_boot_target {
+struct be_cmd_get_boot_target_req {
struct be_cmd_req_hdr hdr;
} __packed;
-struct be_cmd_resp_get_boot_target {
+struct be_cmd_get_boot_target_resp {
struct be_cmd_resp_hdr hdr;
u32 boot_session_count;
int boot_session_handle;
};
-struct be_cmd_req_mac_query {
+struct be_cmd_mac_query_req {
struct be_cmd_req_hdr hdr;
u8 type;
u8 permanent;
u16 if_id;
} __packed;
-struct be_cmd_resp_mac_query {
+struct be_cmd_get_mac_resp {
struct be_cmd_resp_hdr hdr;
struct mac_addr mac;
};
+struct be_ip_addr_subnet_format {
+ u16 size_of_structure;
+ u8 ip_type;
+ u8 ipv6_prefix_length;
+ u8 addr[16];
+ u8 subnet_mask[16];
+ u32 rsvd0;
+} __packed;
+
+struct be_cmd_get_if_info_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_get_if_info_resp {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 vlan_priority;
+ u32 ip_addr_count;
+ u32 dhcp_state;
+ struct be_ip_addr_subnet_format ip_addr;
+} __packed;
+
+struct be_ip_addr_record {
+ u32 action;
+ u32 interface_hndl;
+ struct be_ip_addr_subnet_format ip_addr;
+ u32 status;
+} __packed;
+
+struct be_ip_addr_record_params {
+ u32 record_entry_count;
+ struct be_ip_addr_record ip_record;
+} __packed;
+
+struct be_cmd_set_ip_addr_req {
+ struct be_cmd_req_hdr hdr;
+ struct be_ip_addr_record_params ip_params;
+} __packed;
+
+
+struct be_cmd_set_dhcp_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+ u32 flags;
+ u32 retry_count;
+} __packed;
+
+struct be_cmd_rel_dhcp_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_set_def_gateway_req {
+ struct be_cmd_req_hdr hdr;
+ u32 action;
+ struct ip_addr_format ip_addr;
+} __packed;
+
+struct be_cmd_get_def_gateway_req {
+ struct be_cmd_req_hdr hdr;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_get_def_gateway_resp {
+ struct be_cmd_req_hdr hdr;
+ struct ip_addr_format ip_addr;
+} __packed;
+
/******************** Create CQ ***************************/
/**
* Pseudo amap definition in which each bit of the actual structure is defined
@@ -489,7 +562,7 @@ struct be_cmd_req_modify_eq_delay {
#define ETH_ALEN 6
-struct be_cmd_req_get_mac_addr {
+struct be_cmd_get_nic_conf_req {
struct be_cmd_req_hdr hdr;
u32 nic_port_count;
u32 speed;
@@ -501,7 +574,7 @@ struct be_cmd_req_get_mac_addr {
u32 rsvd[23];
};
-struct be_cmd_resp_get_mac_addr {
+struct be_cmd_get_nic_conf_resp {
struct be_cmd_resp_hdr hdr;
u32 nic_port_count;
u32 speed;
@@ -513,6 +586,39 @@ struct be_cmd_resp_get_mac_addr {
u32 rsvd[23];
};
+#define BEISCSI_ALIAS_LEN 32
+
+struct be_cmd_hba_name {
+ struct be_cmd_req_hdr hdr;
+ u16 flags;
+ u16 rsvd0;
+ u8 initiator_name[ISCSI_NAME_LEN];
+ u8 initiator_alias[BEISCSI_ALIAS_LEN];
+} __packed;
+
+struct be_cmd_ntwk_link_status_req {
+ struct be_cmd_req_hdr hdr;
+ u32 rsvd0;
+} __packed;
+
+/*** Port Speed Values ***/
+#define BE2ISCSI_LINK_SPEED_ZERO 0x00
+#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
+#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
+#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
+#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
+struct be_cmd_ntwk_link_status_resp {
+ struct be_cmd_resp_hdr hdr;
+ u8 phys_port;
+ u8 mac_duplex;
+ u8 mac_speed;
+ u8 mac_fault;
+ u8 mgmt_mac_duplex;
+ u8 mgmt_mac_speed;
+ u16 qos_link_speed;
+ u32 logical_link_speed;
+} __packed;
+
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay);
@@ -530,11 +636,8 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
int be_poll_mcc(struct be_ctrl_info *ctrl);
int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
-unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba);
-unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba);
-unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd);
+unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
+unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
/*ISCSI Functuions */
@@ -715,7 +818,7 @@ struct be_eq_delay_params_in {
struct tcp_connect_and_offload_in {
struct be_cmd_req_hdr hdr;
- struct ip_address_format ip_address;
+ struct ip_addr_format ip_address;
u16 tcp_port;
u16 cid;
u16 cq_id;
@@ -792,13 +895,14 @@ struct be_fw_cfg {
u32 function_caps;
} __packed;
-struct be_all_if_id {
+struct be_cmd_get_all_if_id_req {
struct be_cmd_req_hdr hdr;
u32 if_count;
u32 if_hndl_list[1];
} __packed;
#define ISCSI_OPCODE_SCSI_DATA_OUT 5
+#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
#define OPCODE_COMMON_ISCSI_CLEANUP 59
#define OPCODE_COMMON_TCP_UPLOAD 56
@@ -810,6 +914,8 @@ struct be_all_if_id {
#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41
#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
#define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET 52
+#define OPCODE_COMMON_WRITE_FLASH 96
+#define OPCODE_COMMON_READ_FLASH 97
/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
#define CMD_ISCSI_COMMAND_INVALIDATE 1
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 33c8f09c7ac..43f35034585 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -23,6 +23,8 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_netlink.h>
+#include <net/netlink.h>
#include <scsi/scsi.h>
#include "be_iscsi.h"
@@ -207,6 +209,301 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
}
+static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba)
+{
+ if (phba->ipv4_iface)
+ return 0;
+
+ phba->ipv4_iface = iscsi_create_iface(phba->shost,
+ &beiscsi_iscsi_transport,
+ ISCSI_IFACE_TYPE_IPV4,
+ 0, 0);
+ if (!phba->ipv4_iface) {
+ shost_printk(KERN_ERR, phba->shost, "Could not "
+ "create default IPv4 address.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba)
+{
+ if (phba->ipv6_iface)
+ return 0;
+
+ phba->ipv6_iface = iscsi_create_iface(phba->shost,
+ &beiscsi_iscsi_transport,
+ ISCSI_IFACE_TYPE_IPV6,
+ 0, 0);
+ if (!phba->ipv6_iface) {
+ shost_printk(KERN_ERR, phba->shost, "Could not "
+ "create default IPv6 address.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void beiscsi_create_def_ifaces(struct beiscsi_hba *phba)
+{
+ struct be_cmd_get_if_info_resp if_info;
+
+ if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info))
+ beiscsi_create_ipv4_iface(phba);
+
+ if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info))
+ beiscsi_create_ipv6_iface(phba);
+}
+
+void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba)
+{
+ if (phba->ipv6_iface)
+ iscsi_destroy_iface(phba->ipv6_iface);
+ if (phba->ipv4_iface)
+ iscsi_destroy_iface(phba->ipv4_iface);
+}
+
+static int
+beiscsi_set_static_ip(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_iface_param_info *iface_ip = NULL;
+ struct iscsi_iface_param_info *iface_subnet = NULL;
+ struct nlattr *nla;
+ int ret;
+
+
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
+ if (nla)
+ iface_ip = nla_data(nla);
+
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
+ if (nla)
+ iface_subnet = nla_data(nla);
+ break;
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ iface_ip = iface_param;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
+ if (nla)
+ iface_subnet = nla_data(nla);
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ iface_subnet = iface_param;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
+ if (nla)
+ iface_ip = nla_data(nla);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Unsupported param %d\n",
+ iface_param->param);
+ }
+
+ if (!iface_ip || !iface_subnet) {
+ shost_printk(KERN_ERR, shost, "IP and Subnet Mask required\n");
+ return -EINVAL;
+ }
+
+ ret = mgmt_set_ip(phba, iface_ip, iface_subnet,
+ ISCSI_BOOTPROTO_STATIC);
+
+ return ret;
+}
+
+static int
+beiscsi_set_ipv4(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ int ret = 0;
+
+ /* Check the param */
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IPV4_GW:
+ ret = mgmt_set_gateway(phba, iface_param);
+ break;
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
+ ret = mgmt_set_ip(phba, iface_param,
+ NULL, ISCSI_BOOTPROTO_DHCP);
+ else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
+ ret = beiscsi_set_static_ip(shost, iface_param,
+ data, dt_len);
+ else
+ shost_printk(KERN_ERR, shost, "Invalid BOOTPROTO: %d\n",
+ iface_param->value[0]);
+ break;
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
+ ret = beiscsi_create_ipv4_iface(phba);
+ else
+ iscsi_destroy_iface(phba->ipv4_iface);
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ ret = beiscsi_set_static_ip(shost, iface_param,
+ data, dt_len);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Param %d not supported\n",
+ iface_param->param);
+ }
+
+ return ret;
+}
+
+static int
+beiscsi_set_ipv6(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ int ret = 0;
+
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
+ ret = beiscsi_create_ipv6_iface(phba);
+ else {
+ iscsi_destroy_iface(phba->ipv6_iface);
+ ret = 0;
+ }
+ break;
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ ret = mgmt_set_ip(phba, iface_param, NULL,
+ ISCSI_BOOTPROTO_STATIC);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Param %d not supported\n",
+ iface_param->param);
+ }
+
+ return ret;
+}
+
+int be2iscsi_iface_set_param(struct Scsi_Host *shost,
+ void *data, uint32_t dt_len)
+{
+ struct iscsi_iface_param_info *iface_param = NULL;
+ struct nlattr *attrib;
+ uint32_t rm_len = dt_len;
+ int ret = 0 ;
+
+ nla_for_each_attr(attrib, data, dt_len, rm_len) {
+ iface_param = nla_data(attrib);
+
+ if (iface_param->param_type != ISCSI_NET_PARAM)
+ continue;
+
+ /*
+ * BE2ISCSI only supports 1 interface
+ */
+ if (iface_param->iface_num) {
+ shost_printk(KERN_ERR, shost, "Invalid iface_num %d."
+ "Only iface_num 0 is supported.\n",
+ iface_param->iface_num);
+ return -EINVAL;
+ }
+
+ switch (iface_param->iface_type) {
+ case ISCSI_IFACE_TYPE_IPV4:
+ ret = beiscsi_set_ipv4(shost, iface_param,
+ data, dt_len);
+ break;
+ case ISCSI_IFACE_TYPE_IPV6:
+ ret = beiscsi_set_ipv6(shost, iface_param,
+ data, dt_len);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost,
+ "Invalid iface type :%d passed\n",
+ iface_param->iface_type);
+ break;
+ }
+
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
+ struct iscsi_iface *iface, int param,
+ char *buf)
+{
+ struct be_cmd_get_if_info_resp if_info;
+ int len, ip_type = BE2_IPV4;
+
+ memset(&if_info, 0, sizeof(if_info));
+
+ if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
+ ip_type = BE2_IPV6;
+
+ len = mgmt_get_if_info(phba, ip_type, &if_info);
+ if (len)
+ return len;
+
+ switch (param) {
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ len = sprintf(buf, "%pI4\n", &if_info.ip_addr.addr);
+ break;
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ len = sprintf(buf, "%pI6\n", &if_info.ip_addr.addr);
+ break;
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ if (!if_info.dhcp_state)
+ len = sprintf(buf, "static");
+ else
+ len = sprintf(buf, "dhcp");
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ return len;
+}
+
+int be2iscsi_iface_get_param(struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct be_cmd_get_def_gateway_resp gateway;
+ int len = -ENOSYS;
+
+ switch (param) {
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ len = be2iscsi_get_if_param(phba, iface, param, buf);
+ break;
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ len = sprintf(buf, "enabled");
+ break;
+ case ISCSI_NET_PARAM_IPV4_GW:
+ memset(&gateway, 0, sizeof(gateway));
+ len = mgmt_get_gateway(phba, BE2_IPV4, &gateway);
+ if (!len)
+ len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr);
+ break;
+ default:
+ len = -ENOSYS;
+ }
+
+ return len;
+}
+
/**
* beiscsi_ep_get_param - get the iscsi parameter
* @ep: pointer to iscsi ep
@@ -221,7 +518,7 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
int len = 0;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param);
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_get_param, param= %d\n", param);
switch (param) {
case ISCSI_PARAM_CONN_PORT:
@@ -279,6 +576,121 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
}
/**
+ * beiscsi_get_initname - Read Initiator Name from flash
+ * @buf: buffer bointer
+ * @phba: The device priv structure instance
+ *
+ * returns number of bytes
+ */
+static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
+{
+ int rc;
+ unsigned int tag, wrb_num;
+ unsigned short status, extd_status;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_hba_name *resp;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+
+ tag = be_cmd_get_initname(phba);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "Getting Initiator Name Failed\n");
+ return -EBUSY;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with "
+ "status = %d extd_status = %d\n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -EAGAIN;
+ }
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = embedded_payload(wrb);
+ rc = sprintf(buf, "%s\n", resp->initiator_name);
+ return rc;
+}
+
+/**
+ * beiscsi_get_port_state - Get the Port State
+ * @shost : pointer to scsi_host structure
+ *
+ * returns number of bytes
+ */
+static void beiscsi_get_port_state(struct Scsi_Host *shost)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_cls_host *ihost = shost->shost_data;
+
+ ihost->port_state = (phba->state == BE_ADAPTER_UP) ?
+ ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
+}
+
+/**
+ * beiscsi_get_port_speed - Get the Port Speed from Adapter
+ * @shost : pointer to scsi_host structure
+ *
+ * returns Success/Failure
+ */
+static int beiscsi_get_port_speed(struct Scsi_Host *shost)
+{
+ unsigned int tag, wrb_num;
+ unsigned short status, extd_status;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_ntwk_link_status_resp *resp;
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_cls_host *ihost = shost->shost_data;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+
+ tag = be_cmd_get_port_speed(phba);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "Getting Port Speed Failed\n");
+ return -EBUSY;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with "
+ "status = %d extd_status = %d\n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -EAGAIN;
+ }
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = embedded_payload(wrb);
+
+ switch (resp->mac_speed) {
+ case BE2ISCSI_LINK_SPEED_10MBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_100MBPS:
+ ihost->port_speed = BE2ISCSI_LINK_SPEED_100MBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_1GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_10GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;
+ break;
+ default:
+ ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;
+ }
+ return 0;
+}
+
+/**
* beiscsi_get_host_param - get the iscsi parameter
* @shost: pointer to scsi_host structure
* @param: parameter type identifier
@@ -301,6 +713,27 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
return status;
}
break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ status = beiscsi_get_initname(buf, phba);
+ if (status < 0) {
+ SE_DEBUG(DBG_LVL_1,
+ "Retreiving Initiator Name Failed\n");
+ return status;
+ }
+ break;
+ case ISCSI_HOST_PARAM_PORT_STATE:
+ beiscsi_get_port_state(shost);
+ status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
+ break;
+ case ISCSI_HOST_PARAM_PORT_SPEED:
+ status = beiscsi_get_port_speed(shost);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1,
+ "Retreiving Port Speed Failed\n");
+ return status;
+ }
+ status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
+ break;
default:
return iscsi_host_get_param(shost, param, buf);
}
@@ -309,46 +742,21 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)
{
- struct be_cmd_resp_get_mac_addr *resp;
- struct be_mcc_wrb *wrb;
- unsigned int tag, wrb_num;
- unsigned short status, extd_status;
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_cmd_get_nic_conf_resp resp;
int rc;
- if (phba->read_mac_address)
- return sysfs_format_mac(buf, phba->mac_address,
- ETH_ALEN);
+ if (strlen(phba->mac_address))
+ return strlcpy(buf, phba->mac_address, PAGE_SIZE);
- tag = be_cmd_get_mac_addr(phba);
- if (!tag) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
- return -EBUSY;
- } else
- wait_event_interruptible(phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag]);
+ memset(&resp, 0, sizeof(resp));
+ rc = mgmt_get_nic_conf(phba, &resp);
+ if (rc)
+ return rc;
- wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
- extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
- status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
- if (status || extd_status) {
- SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr"
- " status = %d extd_status = %d\n",
- status, extd_status);
- free_mcc_tag(&phba->ctrl, tag);
- return -EAGAIN;
- }
- wrb = queue_get_wrb(mccq, wrb_num);
- free_mcc_tag(&phba->ctrl, tag);
- resp = embedded_payload(wrb);
- memcpy(phba->mac_address, resp->mac_address, ETH_ALEN);
- rc = sysfs_format_mac(buf, phba->mac_address,
- ETH_ALEN);
- phba->read_mac_address = 1;
- return rc;
+ memcpy(phba->mac_address, resp.mac_address, ETH_ALEN);
+ return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
}
-
/**
* beiscsi_conn_get_stats - get the iscsi stats
* @cls_conn: pointer to iscsi cls conn
@@ -736,11 +1144,24 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
umode_t be2iscsi_attr_is_visible(int param_type, int param)
{
switch (param_type) {
+ case ISCSI_NET_PARAM:
+ switch (param) {
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ case ISCSI_NET_PARAM_IPV4_GW:
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
case ISCSI_HOST_PARAM:
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
- case ISCSI_HOST_PARAM_IPADDRESS:
case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ case ISCSI_HOST_PARAM_PORT_STATE:
+ case ISCSI_HOST_PARAM_PORT_SPEED:
return S_IRUGO;
default:
return 0;
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 5c45be13450..8b826fc06bc 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -25,6 +25,21 @@
#define BE2_IPV4 0x1
#define BE2_IPV6 0x10
+#define BE2_DHCP_V4 0x05
+
+#define NON_BLOCKING 0x0
+#define BLOCKING 0x1
+
+void beiscsi_create_def_ifaces(struct beiscsi_hba *phba);
+
+void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba);
+
+int be2iscsi_iface_get_param(struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf);
+
+int be2iscsi_iface_set_param(struct Scsi_Host *shost,
+ void *data, uint32_t count);
umode_t be2iscsi_attr_is_visible(int param_type, int param);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 375756fa95c..0b1d99c99fd 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -28,8 +28,11 @@
#include <linux/semaphore.h>
#include <linux/iscsi_boot_sysfs.h>
#include <linux/module.h>
+#include <linux/bsg-lib.h>
#include <scsi/libiscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
+#include <scsi/scsi_netlink.h>
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_cmnd.h>
@@ -48,7 +51,8 @@ static unsigned int num_hba = 0;
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
-MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_VERSION(BUILD_STR);
+MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");
module_param(be_iopoll_budget, int, 0);
module_param(enable_msix, int, 0);
@@ -147,15 +151,15 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
- int rc = FAILED;
/* invalidate iocbs */
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
spin_lock_bh(&session->lock);
- if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
- goto unlock;
-
+ if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
+ spin_unlock_bh(&session->lock);
+ return FAILED;
+ }
conn = session->leadconn;
beiscsi_conn = conn->dd_data;
phba = beiscsi_conn->phba;
@@ -208,9 +212,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
-unlock:
- spin_unlock_bh(&session->lock);
- return rc;
}
static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
@@ -230,10 +231,10 @@ static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
case ISCSI_BOOT_TGT_IP_ADDR:
if (boot_conn->dest_ipaddr.ip_type == 0x1)
rc = sprintf(buf, "%pI4\n",
- (char *)&boot_conn->dest_ipaddr.ip_address);
+ (char *)&boot_conn->dest_ipaddr.addr);
else
rc = sprintf(str, "%pI6\n",
- (char *)&boot_conn->dest_ipaddr.ip_address);
+ (char *)&boot_conn->dest_ipaddr.addr);
break;
case ISCSI_BOOT_TGT_PORT:
rc = sprintf(str, "%d\n", boot_conn->dest_port);
@@ -311,12 +312,8 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf)
rc = sprintf(str, "0\n");
break;
case ISCSI_BOOT_ETH_MAC:
- rc = beiscsi_get_macaddr(buf, phba);
- if (rc < 0) {
- SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n");
- return rc;
- }
- break;
+ rc = beiscsi_get_macaddr(str, phba);
+ break;
default:
rc = -ENOSYS;
break;
@@ -394,7 +391,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
static struct scsi_host_template beiscsi_sht = {
.module = THIS_MODULE,
- .name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
+ .name = "Emulex 10Gbe open-iscsi Initiator Driver",
.proc_name = DRV_NAME,
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
@@ -409,6 +406,8 @@ static struct scsi_host_template beiscsi_sht = {
.max_sectors = BEISCSI_MAX_SECTORS,
.cmd_per_lun = BEISCSI_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
+
};
static struct scsi_transport_template *beiscsi_scsi_transport;
@@ -435,6 +434,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
phba->shost = shost;
phba->pcidev = pci_dev_get(pcidev);
pci_set_drvdata(pcidev, phba);
+ phba->interface_handle = 0xFFFFFFFF;
if (iscsi_host_add(shost, &phba->pcidev->dev))
goto free_devices;
@@ -544,8 +544,7 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
&mbox_mem_alloc->dma);
if (!mbox_mem_alloc->va) {
beiscsi_unmap_pci_function(phba);
- status = -ENOMEM;
- return status;
+ return -ENOMEM;
}
mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
@@ -1252,9 +1251,9 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
task = pwrb_handle->pio_handle;
io_task = task->dd_data;
- spin_lock(&phba->mgmt_sgl_lock);
+ spin_lock_bh(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->mgmt_sgl_lock);
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
spin_lock_bh(&session->lock);
free_wrb_handle(phba, pwrb_context, pwrb_handle);
spin_unlock_bh(&session->lock);
@@ -1370,8 +1369,6 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
struct be_bus_address phys_addr;
struct list_head *pbusy_list;
struct async_pdu_handle *pasync_handle = NULL;
- int buffer_len = 0;
- unsigned char buffer_index = -1;
unsigned char is_header = 0;
phys_addr.u.a32.address_lo =
@@ -1392,22 +1389,11 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1,
(pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
index) / 32] & PDUCQE_INDEX_MASK));
-
- buffer_len = (unsigned int)(phys_addr.u.a64.address -
- pasync_ctx->async_header.pa_base.u.a64.address);
-
- buffer_index = buffer_len /
- pasync_ctx->async_header.buffer_size;
-
break;
case UNSOL_DATA_NOTIFY:
pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe->
dw[offsetof(struct amap_i_t_dpdu_cqe,
index) / 32] & PDUCQE_INDEX_MASK));
- buffer_len = (unsigned long)(phys_addr.u.a64.address -
- pasync_ctx->async_data.pa_base.u.
- a64.address);
- buffer_index = buffer_len / pasync_ctx->async_data.buffer_size;
break;
default:
pbusy_list = NULL;
@@ -1418,11 +1404,9 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
return NULL;
}
- WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries));
WARN_ON(list_empty(pbusy_list));
list_for_each_entry(pasync_handle, pbusy_list, link) {
- WARN_ON(pasync_handle->consumed);
- if (pasync_handle->index == buffer_index)
+ if (pasync_handle->pa.u.a64.address == phys_addr.u.a64.address)
break;
}
@@ -1449,15 +1433,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
unsigned int num_entries, writables = 0;
unsigned int *pep_read_ptr, *pwritables;
-
+ num_entries = pasync_ctx->num_entries;
if (is_header) {
pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr;
pwritables = &pasync_ctx->async_header.writables;
- num_entries = pasync_ctx->async_header.num_entries;
} else {
pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr;
pwritables = &pasync_ctx->async_data.writables;
- num_entries = pasync_ctx->async_data.num_entries;
}
while ((*pep_read_ptr) != cq_index) {
@@ -1491,14 +1473,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
return 0;
}
-static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
+static void hwi_free_async_msg(struct beiscsi_hba *phba,
unsigned int cri)
{
struct hwi_controller *phwi_ctrlr;
struct hwi_async_pdu_context *pasync_ctx;
struct async_pdu_handle *pasync_handle, *tmp_handle;
struct list_head *plist;
- unsigned int i = 0;
phwi_ctrlr = phba->phwi_ctrlr;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
@@ -1508,23 +1489,20 @@ static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
list_del(&pasync_handle->link);
- if (i == 0) {
+ if (pasync_handle->is_header) {
list_add_tail(&pasync_handle->link,
&pasync_ctx->async_header.free_list);
pasync_ctx->async_header.free_entries++;
- i++;
} else {
list_add_tail(&pasync_handle->link,
&pasync_ctx->async_data.free_list);
pasync_ctx->async_data.free_entries++;
- i++;
}
}
INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list);
pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0;
pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
- return 0;
}
static struct phys_addr *
@@ -1557,16 +1535,15 @@ static void hwi_post_async_buffers(struct beiscsi_hba *phba,
phwi_ctrlr = phba->phwi_ctrlr;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+ num_entries = pasync_ctx->num_entries;
if (is_header) {
- num_entries = pasync_ctx->async_header.num_entries;
writables = min(pasync_ctx->async_header.writables,
pasync_ctx->async_header.free_entries);
pfree_link = pasync_ctx->async_header.free_list.next;
host_write_num = pasync_ctx->async_header.host_write_ptr;
ring_id = phwi_ctrlr->default_pdu_hdr.id;
} else {
- num_entries = pasync_ctx->async_data.num_entries;
writables = min(pasync_ctx->async_data.writables,
pasync_ctx->async_data.free_entries);
pfree_link = pasync_ctx->async_data.free_list.next;
@@ -1673,7 +1650,7 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
}
memcpy(pfirst_buffer + offset,
pasync_handle->pbuffer, buf_len);
- offset = buf_len;
+ offset += buf_len;
}
index++;
}
@@ -1682,10 +1659,9 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
(beiscsi_conn->beiscsi_conn_cid -
phba->fw_config.iscsi_cid_start),
phdr, hdr_len, pfirst_buffer,
- buf_len);
+ offset);
- if (status == 0)
- hwi_free_async_msg(phba, cri);
+ hwi_free_async_msg(phba, cri);
return 0;
}
@@ -2229,7 +2205,7 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
struct mem_array *mem_arr, *mem_arr_orig;
unsigned int i, j, alloc_size, curr_alloc_size;
- phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
+ phba->phwi_ctrlr = kzalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
if (!phba->phwi_ctrlr)
return -ENOMEM;
@@ -2349,27 +2325,21 @@ static void iscsi_init_global_templates(struct beiscsi_hba *phba)
AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0);
}
-static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
+static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
{
struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb;
- struct wrb_handle *pwrb_handle;
+ struct wrb_handle *pwrb_handle = NULL;
struct hwi_controller *phwi_ctrlr;
struct hwi_wrb_context *pwrb_context;
- struct iscsi_wrb *pwrb;
- unsigned int num_cxn_wrbh;
- unsigned int num_cxn_wrb, j, idx, index;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int num_cxn_wrbh = 0;
+ unsigned int num_cxn_wrb = 0, j, idx = 0, index;
mem_descr_wrbh = phba->init_mem;
mem_descr_wrbh += HWI_MEM_WRBH;
mem_descr_wrb = phba->init_mem;
mem_descr_wrb += HWI_MEM_WRB;
-
- idx = 0;
- pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address;
- num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
- ((sizeof(struct wrb_handle)) *
- phba->params.wrbs_per_cxn));
phwi_ctrlr = phba->phwi_ctrlr;
for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
@@ -2377,12 +2347,32 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_context->pwrb_handle_base =
kzalloc(sizeof(struct wrb_handle *) *
phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (!pwrb_context->pwrb_handle_base) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ goto init_wrb_hndl_failed;
+ }
pwrb_context->pwrb_handle_basestd =
kzalloc(sizeof(struct wrb_handle *) *
phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (!pwrb_context->pwrb_handle_basestd) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ goto init_wrb_hndl_failed;
+ }
+ if (!num_cxn_wrbh) {
+ pwrb_handle =
+ mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ idx++;
+ }
+ pwrb_context->alloc_index = 0;
+ pwrb_context->wrb_handles_available = 0;
+ pwrb_context->free_index = 0;
+
if (num_cxn_wrbh) {
- pwrb_context->alloc_index = 0;
- pwrb_context->wrb_handles_available = 0;
for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
pwrb_context->pwrb_handle_base[j] = pwrb_handle;
pwrb_context->pwrb_handle_basestd[j] =
@@ -2391,49 +2381,21 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_handle->wrb_index = j;
pwrb_handle++;
}
- pwrb_context->free_index = 0;
- num_cxn_wrbh--;
- } else {
- idx++;
- pwrb_handle =
- mem_descr_wrbh->mem_array[idx].virtual_address;
- num_cxn_wrbh =
- ((mem_descr_wrbh->mem_array[idx].size) /
- ((sizeof(struct wrb_handle)) *
- phba->params.wrbs_per_cxn));
- pwrb_context->alloc_index = 0;
- for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
- pwrb_context->pwrb_handle_base[j] = pwrb_handle;
- pwrb_context->pwrb_handle_basestd[j] =
- pwrb_handle;
- pwrb_context->wrb_handles_available++;
- pwrb_handle->wrb_index = j;
- pwrb_handle++;
- }
- pwrb_context->free_index = 0;
num_cxn_wrbh--;
}
}
idx = 0;
- pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
- num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
- ((sizeof(struct iscsi_wrb) *
- phba->params.wrbs_per_cxn));
for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
pwrb_context = &phwi_ctrlr->wrb_context[index];
- if (num_cxn_wrb) {
- for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
- pwrb_handle = pwrb_context->pwrb_handle_base[j];
- pwrb_handle->pwrb = pwrb;
- pwrb++;
- }
- num_cxn_wrb--;
- } else {
- idx++;
+ if (!num_cxn_wrb) {
pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
- ((sizeof(struct iscsi_wrb) *
- phba->params.wrbs_per_cxn));
+ ((sizeof(struct iscsi_wrb) *
+ phba->params.wrbs_per_cxn));
+ idx++;
+ }
+
+ if (num_cxn_wrb) {
for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
pwrb_handle = pwrb_context->pwrb_handle_base[j];
pwrb_handle->pwrb = pwrb;
@@ -2442,6 +2404,14 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
num_cxn_wrb--;
}
}
+ return 0;
+init_wrb_hndl_failed:
+ for (j = index; j > 0; j--) {
+ pwrb_context = &phwi_ctrlr->wrb_context[j];
+ kfree(pwrb_context->pwrb_handle_base);
+ kfree(pwrb_context->pwrb_handle_basestd);
+ }
+ return -ENOMEM;
}
static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
@@ -2450,7 +2420,7 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
struct hba_parameters *p = &phba->params;
struct hwi_async_pdu_context *pasync_ctx;
struct async_pdu_handle *pasync_header_h, *pasync_data_h;
- unsigned int index;
+ unsigned int index, idx, num_per_mem, num_async_data;
struct be_mem_descriptor *mem_descr;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
@@ -2462,10 +2432,8 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx;
memset(pasync_ctx, 0, sizeof(*pasync_ctx));
- pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl;
- pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz;
- pasync_ctx->async_data.buffer_size = p->defpdu_data_sz;
- pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->buffer_size = p->defpdu_hdr_sz;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_BUF;
@@ -2510,19 +2478,6 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_header.writables = 0;
INIT_LIST_HEAD(&pasync_ctx->async_header.free_list);
- mem_descr = (struct be_mem_descriptor *)phba->init_mem;
- mem_descr += HWI_MEM_ASYNC_DATA_BUF;
- if (mem_descr->mem_array[0].virtual_address) {
- SE_DEBUG(DBG_LVL_8,
- "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
- "va=%p\n", mem_descr->mem_array[0].virtual_address);
- } else
- shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address\n");
- pasync_ctx->async_data.va_base =
- mem_descr->mem_array[0].virtual_address;
- pasync_ctx->async_data.pa_base.u.a64.address =
- mem_descr->mem_array[0].bus_address.u.a64.address;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_RING;
@@ -2553,6 +2508,25 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_data_h =
(struct async_pdu_handle *)pasync_ctx->async_data.handle_base;
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address\n");
+ idx = 0;
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[idx].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[idx].bus_address.u.a64.address;
+
+ num_async_data = ((mem_descr->mem_array[idx].size) /
+ phba->params.defpdu_data_sz);
+ num_per_mem = 0;
+
for (index = 0; index < p->asyncpdus_per_ctrl; index++) {
pasync_header_h->cri = -1;
pasync_header_h->index = (char)index;
@@ -2578,14 +2552,29 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_data_h->cri = -1;
pasync_data_h->index = (char)index;
INIT_LIST_HEAD(&pasync_data_h->link);
+
+ if (!num_async_data) {
+ num_per_mem = 0;
+ idx++;
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[idx].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[idx].
+ bus_address.u.a64.address;
+
+ num_async_data = ((mem_descr->mem_array[idx].size) /
+ phba->params.defpdu_data_sz);
+ }
pasync_data_h->pbuffer =
(void *)((unsigned long)
(pasync_ctx->async_data.va_base) +
- (p->defpdu_data_sz * index));
+ (p->defpdu_data_sz * num_per_mem));
pasync_data_h->pa.u.a64.address =
pasync_ctx->async_data.pa_base.u.a64.address +
- (p->defpdu_data_sz * index);
+ (p->defpdu_data_sz * num_per_mem);
+ num_per_mem++;
+ num_async_data--;
list_add_tail(&pasync_data_h->link,
&pasync_ctx->async_data.free_list);
@@ -2913,9 +2902,11 @@ beiscsi_post_pages(struct beiscsi_hba *phba)
static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
- if (mem->va)
+ if (mem->va) {
pci_free_consistent(phba->pcidev, mem->size,
mem->va, mem->dma);
+ mem->va = NULL;
+ }
}
static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q,
@@ -3215,7 +3206,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
error:
shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed");
hwi_cleanup(phba);
- return -ENOMEM;
+ return status;
}
static int hwi_init_controller(struct beiscsi_hba *phba)
@@ -3236,7 +3227,9 @@ static int hwi_init_controller(struct beiscsi_hba *phba)
}
iscsi_init_global_templates(phba);
- beiscsi_init_wrb_handle(phba);
+ if (beiscsi_init_wrb_handle(phba))
+ return -ENOMEM;
+
hwi_init_async_pdu_ctx(phba);
if (hwi_init_port(phba) != 0) {
shost_printk(KERN_ERR, phba->shost,
@@ -3288,7 +3281,7 @@ static int beiscsi_init_controller(struct beiscsi_hba *phba)
free_init:
beiscsi_free_mem(phba);
- return -ENOMEM;
+ return ret;
}
static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
@@ -3475,8 +3468,8 @@ static void hwi_disable_intr(struct beiscsi_hba *phba)
static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
{
- struct be_cmd_resp_get_boot_target *boot_resp;
- struct be_cmd_resp_get_session *session_resp;
+ struct be_cmd_get_boot_target_resp *boot_resp;
+ struct be_cmd_get_session_resp *session_resp;
struct be_mcc_wrb *wrb;
struct be_dma_mem nonemb_cmd;
unsigned int tag, wrb_num;
@@ -3484,9 +3477,9 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
int ret = -ENOMEM;
- tag = beiscsi_get_boot_target(phba);
+ tag = mgmt_get_boot_target(phba);
if (!tag) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+ SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed\n");
return -EAGAIN;
} else
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
@@ -3496,7 +3489,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
if (status || extd_status) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+ SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed"
" status = %d extd_status = %d\n",
status, extd_status);
free_mcc_tag(&phba->ctrl, tag);
@@ -3522,8 +3515,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
}
memset(nonemb_cmd.va, 0, sizeof(*session_resp));
- tag = beiscsi_get_session_info(phba,
- boot_resp->boot_session_handle, &nonemb_cmd);
+ tag = mgmt_get_session_info(phba, boot_resp->boot_session_handle,
+ &nonemb_cmd);
if (!tag) {
SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info"
" Failed\n");
@@ -3696,6 +3689,57 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
kfree(phba->ep_array);
}
+static void beiscsi_cleanup_task(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid
+ - phba->fw_config.iscsi_cid_start];
+
+ if (io_task->cmd_bhs) {
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ io_task->cmd_bhs = NULL;
+ }
+
+ if (task->sc) {
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context,
+ io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->io_sgl_lock);
+ free_io_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->io_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ } else {
+ if (!beiscsi_conn->login_in_progress) {
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context,
+ io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba,
+ io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ }
+ }
+}
+
void
beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_offload_params *params)
@@ -3704,12 +3748,19 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct iscsi_target_context_update_wrb *pwrb = NULL;
struct be_mem_descriptor *mem_descr;
struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_task *task = beiscsi_conn->task;
+ struct iscsi_session *session = task->conn->session;
u32 doorbell = 0;
/*
* We can always use 0 here because it is reserved by libiscsi for
* login/startup related tasks.
*/
+ beiscsi_conn->login_in_progress = 0;
+ spin_lock_bh(&session->lock);
+ beiscsi_cleanup_task(task);
+ spin_unlock_bh(&session->lock);
+
pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid -
phba->fw_config.iscsi_cid_start));
pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
@@ -3823,7 +3874,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
task->hdr_max = sizeof(struct be_cmd_bhs);
io_task->psgl_handle = NULL;
- io_task->psgl_handle = NULL;
+ io_task->pwrb_handle = NULL;
if (task->sc) {
spin_lock(&phba->io_sgl_lock);
@@ -3865,6 +3916,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->pwrb_handle =
beiscsi_conn->plogin_wrb_handle;
}
+ beiscsi_conn->task = task;
} else {
spin_lock(&phba->mgmt_sgl_lock);
io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
@@ -3907,53 +3959,11 @@ free_hndls:
io_task->pwrb_handle = NULL;
pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
io_task->bhs_pa.u.a64.address);
+ io_task->cmd_bhs = NULL;
SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n");
return -ENOMEM;
}
-static void beiscsi_cleanup_task(struct iscsi_task *task)
-{
- struct beiscsi_io_task *io_task = task->dd_data;
- struct iscsi_conn *conn = task->conn;
- struct beiscsi_conn *beiscsi_conn = conn->dd_data;
- struct beiscsi_hba *phba = beiscsi_conn->phba;
- struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
- struct hwi_wrb_context *pwrb_context;
- struct hwi_controller *phwi_ctrlr;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid
- - phba->fw_config.iscsi_cid_start];
- if (io_task->pwrb_handle) {
- free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
- io_task->pwrb_handle = NULL;
- }
-
- if (io_task->cmd_bhs) {
- pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
- io_task->bhs_pa.u.a64.address);
- }
-
- if (task->sc) {
- if (io_task->psgl_handle) {
- spin_lock(&phba->io_sgl_lock);
- free_io_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->io_sgl_lock);
- io_task->psgl_handle = NULL;
- }
- } else {
- if (task->hdr &&
- ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN))
- return;
- if (io_task->psgl_handle) {
- spin_lock(&phba->mgmt_sgl_lock);
- free_mgmt_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->mgmt_sgl_lock);
- io_task->psgl_handle = NULL;
- }
- }
-}
-
static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
unsigned int num_sg, unsigned int xferlen,
unsigned int writedir)
@@ -3993,7 +4003,8 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
&io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun));
AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb,
- cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun));
+ cpu_to_be16(*(unsigned short *)
+ &io_task->cmd_bhs->iscsi_hdr.lun));
AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen);
AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
io_task->pwrb_handle->wrb_index);
@@ -4126,6 +4137,76 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
}
+/**
+ * beiscsi_bsg_request - handle bsg request from ISCSI transport
+ * @job: job to handle
+ */
+static int beiscsi_bsg_request(struct bsg_job *job)
+{
+ struct Scsi_Host *shost;
+ struct beiscsi_hba *phba;
+ struct iscsi_bsg_request *bsg_req = job->request;
+ int rc = -EINVAL;
+ unsigned int tag;
+ struct be_dma_mem nonemb_cmd;
+ struct be_cmd_resp_hdr *resp;
+ struct iscsi_bsg_reply *bsg_reply = job->reply;
+ unsigned short status, extd_status;
+
+ shost = iscsi_job_to_shost(job);
+ phba = iscsi_host_priv(shost);
+
+ switch (bsg_req->msgcode) {
+ case ISCSI_BSG_HST_VENDOR:
+ nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ job->request_payload.payload_len,
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for "
+ "beiscsi_bsg_request\n");
+ return -EIO;
+ }
+ tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job,
+ &nonemb_cmd);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return -EAGAIN;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va;
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ nonemb_cmd.va, (resp->response_length
+ + sizeof(*resp)));
+ bsg_reply->reply_payload_rcv_len = resp->response_length;
+ bsg_reply->result = status;
+ bsg_job_done(job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+ " status = %d extd_status = %d\n",
+ status, extd_status);
+ return -EIO;
+ }
+ break;
+
+ default:
+ SE_DEBUG(DBG_LVL_1, "Unsupported bsg command: 0x%x\n",
+ bsg_req->msgcode);
+ break;
+ }
+
+ return rc;
+}
+
static void beiscsi_quiesce(struct beiscsi_hba *phba)
{
struct hwi_controller *phwi_ctrlr;
@@ -4183,6 +4264,7 @@ static void beiscsi_remove(struct pci_dev *pcidev)
return;
}
+ beiscsi_destroy_def_ifaces(phba);
beiscsi_quiesce(phba);
iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
@@ -4267,8 +4349,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
phba->num_cpus = num_cpus;
SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus);
- if (enable_msix)
+ if (enable_msix) {
beiscsi_msix_enable(phba);
+ if (!phba->msix_enabled)
+ phba->num_cpus = 1;
+ }
ret = be_ctrl_init(phba, pcidev);
if (ret) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
@@ -4366,8 +4451,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
* iscsi boot.
*/
shost_printk(KERN_ERR, phba->shost, "Could not set up "
- "iSCSI boot info.");
+ "iSCSI boot info.\n");
+ beiscsi_create_def_ifaces(phba);
SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n");
return 0;
@@ -4418,6 +4504,8 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.bind_conn = beiscsi_conn_bind,
.destroy_conn = iscsi_conn_teardown,
.attr_is_visible = be2iscsi_attr_is_visible,
+ .set_iface_param = be2iscsi_iface_set_param,
+ .get_iface_param = be2iscsi_iface_get_param,
.set_param = beiscsi_set_param,
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
@@ -4435,6 +4523,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.ep_poll = beiscsi_ep_poll,
.ep_disconnect = beiscsi_ep_disconnect,
.session_recovery_timedout = iscsi_session_recovery_timedout,
+ .bsg_request = beiscsi_bsg_request,
};
static struct pci_driver beiscsi_pci_driver = {
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index b4a06d5e5f9..40fea6ec879 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -34,9 +34,9 @@
#include "be.h"
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "4.1.239.0"
-#define BE_NAME "ServerEngines BladeEngine2" \
- "Linux iSCSI Driver version" BUILD_STR
+#define BUILD_STR "4.2.162.0"
+#define BE_NAME "Emulex OneConnect" \
+ "Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
#define BE_VENDOR_ID 0x19A2
@@ -316,6 +316,8 @@ struct beiscsi_hba {
struct iscsi_endpoint **ep_array;
struct iscsi_boot_kset *boot_kset;
struct Scsi_Host *shost;
+ struct iscsi_iface *ipv4_iface;
+ struct iscsi_iface *ipv6_iface;
struct {
/**
* group together since they are used most frequently
@@ -345,7 +347,7 @@ struct beiscsi_hba {
struct work_struct work_cqs; /* The work being queued */
struct be_ctrl_info ctrl;
unsigned int generation;
- unsigned int read_mac_address;
+ unsigned int interface_handle;
struct mgmt_session_info boot_sess;
struct invalidate_command_table inv_tbl[128];
@@ -525,8 +527,6 @@ struct hwi_async_pdu_context {
unsigned int free_entries;
unsigned int busy_entries;
- unsigned int buffer_size;
- unsigned int num_entries;
struct list_head free_list;
} async_header;
@@ -543,11 +543,12 @@ struct hwi_async_pdu_context {
unsigned int free_entries;
unsigned int busy_entries;
- unsigned int buffer_size;
struct list_head free_list;
- unsigned int num_entries;
} async_data;
+ unsigned int buffer_size;
+ unsigned int num_entries;
+
/**
* This is a varying size list! Do not add anything
* after this entry!!
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 44762cfa3e1..01bb04cd9e7 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -17,15 +17,17 @@
* Costa Mesa, CA 92626
*/
+#include <linux/bsg-lib.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
#include "be_mgmt.h"
#include "be_iscsi.h"
-#include <scsi/scsi_transport_iscsi.h>
-unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba)
+unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
- struct be_cmd_req_get_mac_addr *req;
+ struct be_cmd_get_boot_target_req *req;
unsigned int tag = 0;
SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n");
@@ -42,22 +44,22 @@ unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba)
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
- sizeof(*req));
+ sizeof(struct be_cmd_get_boot_target_resp));
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
return tag;
}
-unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd)
+unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
+ u32 boot_session_handle,
+ struct be_dma_mem *nonemb_cmd)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
unsigned int tag = 0;
- struct be_cmd_req_get_session *req;
- struct be_cmd_resp_get_session *resp;
+ struct be_cmd_get_session_req *req;
+ struct be_cmd_get_session_resp *resp;
struct be_sge *sge;
SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n");
@@ -187,6 +189,72 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
return status;
}
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba,
+ struct bsg_job *job,
+ struct be_dma_mem *nonemb_cmd)
+{
+ struct be_cmd_resp_hdr *resp;
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+ struct be_sge *mcc_sge = nonembedded_sgl(wrb);
+ unsigned int tag = 0;
+ struct iscsi_bsg_request *bsg_req = job->request;
+ struct be_bsg_vendor_cmd *req = nonemb_cmd->va;
+ unsigned short region, sector_size, sector, offset;
+
+ nonemb_cmd->size = job->request_payload.payload_len;
+ memset(nonemb_cmd->va, 0, nonemb_cmd->size);
+ resp = nonemb_cmd->va;
+ region = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
+ sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+ sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3];
+ offset = bsg_req->rqst_data.h_vendor.vendor_cmd[4];
+ req->region = region;
+ req->sector = sector;
+ req->offset = offset;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
+ case BEISCSI_WRITE_FLASH:
+ offset = sector * sector_size + offset;
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_WRITE_FLASH, sizeof(*req));
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ nonemb_cmd->va + offset, job->request_len);
+ break;
+ case BEISCSI_READ_FLASH:
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_READ_FLASH, sizeof(*req));
+ break;
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unsupported cmd = 0x%x\n\n", bsg_req->rqst_data.
+ h_vendor.vendor_cmd[0]);
+ spin_unlock(&ctrl->mbox_lock);
+ return -ENOSYS;
+ }
+
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
+ job->request_payload.sg_cnt);
+ mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
+ wrb->tag0 |= tag;
+
+ be_mcc_notify(phba);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+}
+
int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
@@ -328,7 +396,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr *dst_addr,
struct beiscsi_endpoint *beiscsi_ep,
struct be_dma_mem *nonemb_cmd)
-
{
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
@@ -374,17 +441,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
if (dst_addr->sa_family == PF_INET) {
__be32 s_addr = daddr_in->sin_addr.s_addr;
req->ip_address.ip_type = BE2_IPV4;
- req->ip_address.ip_address[0] = s_addr & 0x000000ff;
- req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8;
- req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16;
- req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24;
+ req->ip_address.addr[0] = s_addr & 0x000000ff;
+ req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8;
+ req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16;
+ req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24;
req->tcp_port = ntohs(daddr_in->sin_port);
beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
beiscsi_ep->ip_type = BE2_IPV4;
} else if (dst_addr->sa_family == PF_INET6) {
req->ip_address.ip_type = BE2_IPV6;
- memcpy(&req->ip_address.ip_address,
+ memcpy(&req->ip_address.addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
req->tcp_port = ntohs(daddr_in6->sin6_port);
beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
@@ -419,14 +486,399 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
return tag;
}
-unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba)
+unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_req_get_mac_addr *req;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb);
+ struct be_cmd_get_all_if_id_req *pbe_allid = req;
+ int status = 0;
+
+ memset(wrb, 0, sizeof(*wrb));
+
+ spin_lock(&ctrl->mbox_lock);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
+ sizeof(*req));
+ status = be_mbox_notify(ctrl);
+ if (!status)
+ phba->interface_handle = pbe_allid->if_hndl_list[0];
+ else {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed in mgmt_get_all_if_id\n");
+ }
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
+ struct be_dma_mem *nonemb_cmd, void *resp_buf,
+ int resp_buf_len)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+ unsigned short status, extd_status;
+ struct be_sge *sge;
+ unsigned int tag;
+ int rc = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ rc = -ENOMEM;
+ goto free_cmd;
+ }
+ memset(wrb, 0, sizeof(*wrb));
+ wrb->tag0 |= tag;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
+
+ be_mcc_notify(phba);
+ spin_unlock(&ctrl->mbox_lock);
+
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1,
+ "mgmt_exec_nonemb_cmd Failed status = %d"
+ "extd_status = %d\n", status, extd_status);
+ rc = -EIO;
+ goto free_tag;
+ }
+
+ if (resp_buf)
+ memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
+
+free_tag:
+ free_mcc_tag(&phba->ctrl, tag);
+free_cmd:
+ pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
+ nonemb_cmd->va, nonemb_cmd->dma);
+ return rc;
+}
+
+static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd,
+ int iscsi_cmd, int size)
+{
+ cmd->va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(size),
+ &cmd->dma);
+ if (!cmd->va) {
+ SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for if info\n");
+ return -ENOMEM;
+ }
+ memset(cmd->va, 0, sizeof(size));
+ cmd->size = size;
+ be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size);
+ return 0;
+}
+
+static int
+mgmt_static_ip_modify(struct beiscsi_hba *phba,
+ struct be_cmd_get_if_info_resp *if_info,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t ip_action)
+{
+ struct be_cmd_set_ip_addr_req *req;
+ struct be_dma_mem nonemb_cmd;
+ uint32_t ip_type;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
+ sizeof(*req));
+ if (rc)
+ return rc;
+
+ ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ BE2_IPV6 : BE2_IPV4 ;
+
+ req = nonemb_cmd.va;
+ req->ip_params.record_entry_count = 1;
+ req->ip_params.ip_record.action = ip_action;
+ req->ip_params.ip_record.interface_hndl =
+ phba->interface_handle;
+ req->ip_params.ip_record.ip_addr.size_of_structure =
+ sizeof(struct be_ip_addr_subnet_format);
+ req->ip_params.ip_record.ip_addr.ip_type = ip_type;
+
+ if (ip_action == IP_ACTION_ADD) {
+ memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value,
+ ip_param->len);
+
+ if (subnet_param)
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ subnet_param->value, subnet_param->len);
+ } else {
+ memcpy(req->ip_params.ip_record.ip_addr.addr,
+ if_info->ip_addr.addr, ip_param->len);
+
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ if_info->ip_addr.subnet_mask, ip_param->len);
+ }
+
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0)
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Modify existing IP Address\n");
+ return rc;
+}
+
+static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr,
+ uint32_t gtway_action, uint32_t param_len)
+{
+ struct be_cmd_set_def_gateway_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rt_val;
+
+
+ rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY,
+ sizeof(*req));
+ if (rt_val)
+ return rt_val;
+
+ req = nonemb_cmd.va;
+ req->action = gtway_action;
+ req->ip_addr.ip_type = BE2_IPV4;
+
+ memcpy(req->ip_addr.addr, gt_addr, param_len);
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+}
+
+int mgmt_set_ip(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t boot_proto)
+{
+ struct be_cmd_get_def_gateway_resp gtway_addr_set;
+ struct be_cmd_get_if_info_resp if_info;
+ struct be_cmd_set_dhcp_req *dhcpreq;
+ struct be_cmd_rel_dhcp_req *reldhcp;
+ struct be_dma_mem nonemb_cmd;
+ uint8_t *gtway_addr;
+ uint32_t ip_type;
+ int rc;
+
+ if (mgmt_get_all_if_id(phba))
+ return -EIO;
+
+ memset(&if_info, 0, sizeof(if_info));
+ ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ BE2_IPV6 : BE2_IPV4 ;
+
+ rc = mgmt_get_if_info(phba, ip_type, &if_info);
+ if (rc)
+ return rc;
+
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ if (if_info.dhcp_state) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "DHCP Already Enabled\n");
+ return 0;
+ }
+ /* The ip_param->len is 1 in DHCP case. Setting
+ proper IP len as this it is used while
+ freeing the Static IP.
+ */
+ ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ IP_V6_LEN : IP_V4_LEN;
+
+ } else {
+ if (if_info.dhcp_state) {
+
+ memset(&if_info, 0, sizeof(if_info));
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR,
+ sizeof(*reldhcp));
+
+ if (rc)
+ return rc;
+
+ reldhcp = nonemb_cmd.va;
+ reldhcp->interface_hndl = phba->interface_handle;
+ reldhcp->ip_type = ip_type;
+
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Delete existing dhcp\n");
+ return rc;
+ }
+ }
+ }
+
+ /* Delete the Static IP Set */
+ if (if_info.ip_addr.addr[0]) {
+ rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL,
+ IP_ACTION_DEL);
+ if (rc)
+ return rc;
+ }
+
+ /* Delete the Gateway settings if mode change is to DHCP */
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
+ rc = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
+ if (rc) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Get Gateway Addr\n");
+ return rc;
+ }
+
+ if (gtway_addr_set.ip_addr.addr[0]) {
+ gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
+ rc = mgmt_modify_gateway(phba, gtway_addr,
+ IP_ACTION_DEL, IP_V4_LEN);
+
+ if (rc) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to clear Gateway Addr Set\n");
+ return rc;
+ }
+ }
+ }
+
+ /* Set Adapter to DHCP/Static Mode */
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR,
+ sizeof(*dhcpreq));
+ if (rc)
+ return rc;
+
+ dhcpreq = nonemb_cmd.va;
+ dhcpreq->flags = BLOCKING;
+ dhcpreq->retry_count = 1;
+ dhcpreq->interface_hndl = phba->interface_handle;
+ dhcpreq->ip_type = BE2_DHCP_V4;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ } else {
+ return mgmt_static_ip_modify(phba, &if_info, ip_param,
+ subnet_param, IP_ACTION_ADD);
+ }
+
+ return rc;
+}
+
+int mgmt_set_gateway(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *gateway_param)
+{
+ struct be_cmd_get_def_gateway_resp gtway_addr_set;
+ uint8_t *gtway_addr;
+ int rt_val;
+
+ memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
+ rt_val = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
+ if (rt_val) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Get Gateway Addr\n");
+ return rt_val;
+ }
+
+ if (gtway_addr_set.ip_addr.addr[0]) {
+ gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
+ rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL,
+ gateway_param->len);
+ if (rt_val) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to clear Gateway Addr Set\n");
+ return rt_val;
+ }
+ }
+
+ gtway_addr = (uint8_t *)&gateway_param->value;
+ rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD,
+ gateway_param->len);
+
+ if (rt_val)
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Set Gateway Addr\n");
+
+ return rt_val;
+}
+
+int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_def_gateway_resp *gateway)
+{
+ struct be_cmd_get_def_gateway_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY,
+ sizeof(*gateway));
+ if (rc)
+ return rc;
+
+ req = nonemb_cmd.va;
+ req->ip_type = ip_type;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway,
+ sizeof(*gateway));
+}
+
+int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp *if_info)
+{
+ struct be_cmd_get_if_info_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ if (mgmt_get_all_if_id(phba))
+ return -EIO;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO,
+ sizeof(*if_info));
+ if (rc)
+ return rc;
+
+ req = nonemb_cmd.va;
+ req->interface_hndl = phba->interface_handle;
+ req->ip_type = ip_type;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info,
+ sizeof(*if_info));
+}
+
+int mgmt_get_nic_conf(struct beiscsi_hba *phba,
+ struct be_cmd_get_nic_conf_resp *nic)
+{
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
+ sizeof(*nic));
+ if (rc)
+ return rc;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, nic, sizeof(*nic));
+}
+
+
+
+unsigned int be_cmd_get_initname(struct beiscsi_hba *phba)
+{
unsigned int tag = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_hba_name *req;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
- SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n");
spin_lock(&ctrl->mbox_lock);
tag = alloc_mcc_tag(phba);
if (!tag) {
@@ -438,12 +890,38 @@ unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba)
req = embedded_payload(wrb);
wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
- OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
- sizeof(*req));
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_CFG_GET_HBA_NAME,
+ sizeof(*req));
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
return tag;
}
+unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba)
+{
+ unsigned int tag = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_ntwk_link_status_req *req;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ spin_lock(&ctrl->mbox_lock);
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+
+ wrb = wrb_from_mccq(phba);
+ req = embedded_payload(wrb);
+ wrb->tag0 |= tag;
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY,
+ sizeof(*req));
+
+ be_mcc_notify(phba);
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 08428824ace..5c2e37693ca 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -20,11 +20,16 @@
#ifndef _BEISCSI_MGMT_
#define _BEISCSI_MGMT_
-#include <linux/types.h>
-#include <linux/list.h>
+#include <scsi/scsi_bsg_iscsi.h>
#include "be_iscsi.h"
#include "be_main.h"
+#define IP_ACTION_ADD 0x01
+#define IP_ACTION_DEL 0x02
+
+#define IP_V6_LEN 16
+#define IP_V4_LEN 4
+
/**
* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field
@@ -98,6 +103,10 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct invalidate_command_table *inv_tbl,
unsigned int num_invalidate, unsigned int cid,
struct be_dma_mem *nonemb_cmd);
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba,
+ struct bsg_job *job,
+ struct be_dma_mem *nonemb_cmd);
struct iscsi_invalidate_connection_params_in {
struct be_cmd_req_hdr hdr;
@@ -204,6 +213,13 @@ struct be_mgmt_controller_attributes_resp {
struct mgmt_controller_attributes params;
} __packed;
+struct be_bsg_vendor_cmd {
+ struct be_cmd_req_hdr hdr;
+ unsigned short region;
+ unsigned short offset;
+ unsigned short sector;
+} __packed;
+
/* configuration management */
#define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws)
@@ -219,12 +235,15 @@ struct be_mgmt_controller_attributes_resp {
/* the CMD_RESPONSE_HEADER */
#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\
- pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
bus_address.u.a32.address_lo; \
- pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
bus_address.u.a32.address_hi; \
}
+#define BEISCSI_WRITE_FLASH 0
+#define BEISCSI_READ_FLASH 1
+
struct beiscsi_endpoint {
struct beiscsi_hba *phba;
struct beiscsi_sess *sess;
@@ -248,4 +267,27 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short issue_reset,
unsigned short savecfg_flag);
+int mgmt_set_ip(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t boot_proto);
+
+unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba);
+
+unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
+ u32 boot_session_handle,
+ struct be_dma_mem *nonemb_cmd);
+
+int mgmt_get_nic_conf(struct beiscsi_hba *phba,
+ struct be_cmd_get_nic_conf_resp *mac);
+
+int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp *if_info);
+
+int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_def_gateway_resp *gateway);
+
+int mgmt_set_gateway(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *gateway_param);
+
#endif
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index e75e07d2591..51c9e134571 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -799,9 +799,6 @@ struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad,
enum bfa_lport_role roles,
struct bfad_vf_s *vf_drv,
struct bfad_vport_s *vp_drv);
-void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
- struct bfad_vf_s *vf_drv,
- struct bfad_vport_s *vp_drv);
/*
* vport callbacks
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 5d2a1307e5c..937000db62a 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -616,7 +616,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
__port_action[port->fabric->fab_type].online(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port online: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE);
@@ -639,12 +639,12 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
if (bfa_sm_cmp_state(port->fabric,
bfa_fcs_fabric_sm_online) == BFA_TRUE) {
- BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
} else {
- BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port taken offline: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE);
@@ -709,14 +709,10 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);
/* Base port will be deleted by the OS driver */
- if (port->vport) {
- bfa_fcb_lport_delete(port->fcs->bfad, port->port_cfg.roles,
- port->fabric->vf_drv,
- port->vport ? port->vport->vport_drv : NULL);
+ if (port->vport)
bfa_fcs_vport_delete_comp(port->vport);
- } else {
+ else
bfa_wc_down(&port->fabric->wc);
- }
}
@@ -5714,17 +5710,23 @@ bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
(struct bfad_vport_s *)vport->vport_drv;
bfa_fcs_fabric_delvport(__vport_fabric(vport), vport);
+ bfa_lps_delete(vport->lps);
- if (vport_drv->comp_del)
+ if (vport_drv->comp_del) {
complete(vport_drv->comp_del);
- else
- kfree(vport_drv);
+ return;
+ }
- bfa_lps_delete(vport->lps);
+ /*
+ * We queue the vport delete work to the IM work_q from here.
+ * The memory for the bfad_vport_s is freed from the FC function
+ * template vport_delete entry point.
+ */
+ if (vport_drv)
+ bfad_im_port_delete(vport_drv->drv_port.bfad,
+ &vport_drv->drv_port);
}
-
-
/*
* fcs_vport_public FCS virtual port public interfaces
*/
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 404fd10ddb2..2e4b0be14a2 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -456,23 +456,6 @@ bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port,
return port_drv;
}
-void
-bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
- struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
-{
- struct bfad_port_s *port_drv;
-
- /* this will be only called from rmmod context */
- if (vp_drv && !vp_drv->comp_del) {
- port_drv = (vp_drv) ? (&(vp_drv)->drv_port) :
- ((vf_drv) ? (&(vf_drv)->base_port) :
- (&(bfad)->pport));
- bfa_trc(bfad, roles);
- if (roles & BFA_LPORT_ROLE_FCP_IM)
- bfad_im_port_delete(bfad, port_drv);
- }
-}
-
/*
* FCS RPORT alloc callback, after successful PLOGI by FCS
*/
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 7b1ecd2b3ff..8b6c6bf7837 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -497,6 +497,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
if (im_port->flags & BFAD_PORT_DELETE) {
bfad_scsi_host_free(bfad, im_port);
list_del(&vport->list_entry);
+ kfree(vport);
return 0;
}
@@ -758,25 +759,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
else if (!strcmp(model, "Brocade-804"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 8Gbps FC HBA for HP Bladesystem C-class");
- else if (!strcmp(model, "Brocade-902") ||
- !strcmp(model, "Brocade-1741"))
+ else if (!strcmp(model, "Brocade-1741"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 10Gbps CNA for Dell M-Series Blade Servers");
- else if (strstr(model, "Brocade-1560")) {
- if (nports == 1)
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA");
- else
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA");
- } else if (strstr(model, "Brocade-1710")) {
- if (nports == 1)
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
- else
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
- } else if (strstr(model, "Brocade-1860")) {
+ else if (strstr(model, "Brocade-1860")) {
if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 10Gbps single port CNA");
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 495a841645f..25093a04123 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index 72118db89a2..dc0a08e69c8 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 0bd70e80efe..0c53c28dc3d 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index f9d6f412909..ece47e50228 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 4927cca733d..8b6816706ee 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.7.0.3"
-#define DRV_MODULE_RELDATE "Jun 15, 2011"
+#define DRV_MODULE_VERSION "2.7.2.2"
+#define DRV_MODULE_RELDATE "Apr 25, 2012"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 1a44b45e7be..f8d516b5316 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -2244,6 +2244,7 @@ static struct scsi_host_template bnx2i_host_template = {
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_recover_target,
.change_queue_depth = iscsi_change_queue_depth,
+ .target_alloc = iscsi_target_alloc,
.can_queue = 2048,
.max_sectors = 127,
.cmd_per_lun = 128,
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index 83a77f7244d..c61cf7a4365 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,6 +1,6 @@
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2011 Broadcom Corporation
+ * Copyright (c) 2004 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 04c5cea47a2..fda9cdea0e6 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -55,11 +55,16 @@
#define ALUA_FAILOVER_TIMEOUT (60 * HZ)
#define ALUA_FAILOVER_RETRIES 5
+/* flags passed from user level */
+#define ALUA_OPTIMIZE_STPG 1
+
struct alua_dh_data {
int group_id;
int rel_port;
int tpgs;
int state;
+ int pref;
+ unsigned flags; /* used for optimizing STPG */
unsigned char inq[ALUA_INQUIRY_SIZE];
unsigned char *buff;
int bufflen;
@@ -554,14 +559,16 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
if (h->group_id == (ucp[2] << 8) + ucp[3]) {
h->state = ucp[0] & 0x0f;
+ h->pref = ucp[0] >> 7;
valid_states = ucp[1];
}
off = 8 + (ucp[7] * 4);
}
sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n",
+ "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
+ h->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -621,6 +628,37 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
out:
return err;
}
+/*
+ * alua_set_params - set/unset the optimize flag
+ * @sdev: device on the path to be activated
+ * params - parameters in the following format
+ * "no_of_params\0param1\0param2\0param3\0...\0"
+ * For example, to set the flag pass the following parameters
+ * from multipath.conf
+ * hardware_handler "2 alua 1"
+ */
+static int alua_set_params(struct scsi_device *sdev, const char *params)
+{
+ struct alua_dh_data *h = get_alua_data(sdev);
+ unsigned int optimize = 0, argc;
+ const char *p = params;
+ int result = SCSI_DH_OK;
+
+ if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
+ return -EINVAL;
+
+ while (*p++)
+ ;
+ if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
+ return -EINVAL;
+
+ if (optimize)
+ h->flags |= ALUA_OPTIMIZE_STPG;
+ else
+ h->flags &= ~ALUA_OPTIMIZE_STPG;
+
+ return result;
+}
/*
* alua_activate - activate a path
@@ -637,14 +675,37 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = get_alua_data(sdev);
int err = SCSI_DH_OK;
+ int stpg = 0;
err = alua_rtpg(sdev, h);
if (err != SCSI_DH_OK)
goto out;
- if (h->tpgs & TPGS_MODE_EXPLICIT &&
- h->state != TPGS_STATE_OPTIMIZED &&
- h->state != TPGS_STATE_LBA_DEPENDENT) {
+ if (h->tpgs & TPGS_MODE_EXPLICIT) {
+ switch (h->state) {
+ case TPGS_STATE_NONOPTIMIZED:
+ stpg = 1;
+ if ((h->flags & ALUA_OPTIMIZE_STPG) &&
+ (!h->pref) &&
+ (h->tpgs & TPGS_MODE_IMPLICIT))
+ stpg = 0;
+ break;
+ case TPGS_STATE_STANDBY:
+ stpg = 1;
+ break;
+ case TPGS_STATE_UNAVAILABLE:
+ case TPGS_STATE_OFFLINE:
+ err = SCSI_DH_IO;
+ break;
+ case TPGS_STATE_TRANSITIONING:
+ err = SCSI_DH_RETRY;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (stpg) {
h->callback_fn = fn;
h->callback_data = data;
err = submit_stpg(h);
@@ -698,6 +759,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+ .set_params = alua_set_params,
.match = alua_match,
};
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 335e8519280..76e3d0b5bfa 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -411,20 +411,18 @@ out:
}
/**
- * fcoe_interface_cleanup() - Clean up a FCoE interface
+ * fcoe_interface_remove() - remove FCoE interface from netdev
* @fcoe: The FCoE interface to be cleaned up
*
* Caller must be holding the RTNL mutex
*/
-static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
+static void fcoe_interface_remove(struct fcoe_interface *fcoe)
{
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = &fcoe->ctlr;
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
- rtnl_lock();
-
/*
* Don't listen for Ethernet packets anymore.
* synchronize_net() ensures that the packet handlers are not running
@@ -453,12 +451,28 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
" specific feature for LLD.\n");
}
+ fcoe->removed = 1;
+}
+
+
+/**
+ * fcoe_interface_cleanup() - Clean up a FCoE interface
+ * @fcoe: The FCoE interface to be cleaned up
+ */
+static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
+{
+ struct net_device *netdev = fcoe->netdev;
+ struct fcoe_ctlr *fip = &fcoe->ctlr;
+ rtnl_lock();
+ if (!fcoe->removed)
+ fcoe_interface_remove(fcoe);
rtnl_unlock();
/* Release the self-reference taken during fcoe_interface_create() */
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(fip);
+ scsi_host_put(fcoe->ctlr.lp->host);
kfree(fcoe);
dev_put(netdev);
module_put(THIS_MODULE);
@@ -522,13 +536,11 @@ static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr)
struct fcoe_port *port = lport_priv(lport);
struct fcoe_interface *fcoe = port->priv;
- rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(fcoe->netdev, port->data_src_addr);
if (!is_zero_ether_addr(addr))
dev_uc_add(fcoe->netdev, addr);
memcpy(port->data_src_addr, addr, ETH_ALEN);
- rtnl_unlock();
}
/**
@@ -941,6 +953,10 @@ static void fcoe_if_destroy(struct fc_lport *lport)
rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(netdev, port->data_src_addr);
+ if (lport->vport)
+ synchronize_net();
+ else
+ fcoe_interface_remove(fcoe);
rtnl_unlock();
/* Free queued packets for the per-CPU receive threads */
@@ -959,8 +975,12 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Free memory used by statistical counters */
fc_lport_free_stats(lport);
- /* Release the Scsi_Host */
- scsi_host_put(lport->host);
+ /*
+ * Release the Scsi_Host for vport but hold on to
+ * master lport until it fcoe interface fully cleaned-up.
+ */
+ if (lport->vport)
+ scsi_host_put(lport->host);
}
/**
@@ -2274,10 +2294,9 @@ static void fcoe_percpu_clean(struct fc_lport *lport)
continue;
skb = dev_alloc_skb(0);
- if (!skb) {
- spin_unlock_bh(&pp->fcoe_rx_list.lock);
+ if (!skb)
continue;
- }
+
skb->destructor = fcoe_percpu_flush_done;
spin_lock_bh(&pp->fcoe_rx_list.lock);
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index 3c2733a12aa..96ac938d39c 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -71,7 +71,8 @@ do { \
* @ctlr: The FCoE controller (for FIP)
* @oem: The offload exchange manager for all local port
* instances associated with this port
- * This structure is 1:1 with a net devive.
+ * @removed: Indicates fcoe interface removed from net device
+ * This structure is 1:1 with a net device.
*/
struct fcoe_interface {
struct list_head list;
@@ -81,6 +82,7 @@ struct fcoe_interface {
struct packet_type fip_packet_type;
struct fcoe_ctlr ctlr;
struct fc_exch_mgr *oem;
+ u8 removed;
};
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 249a106888d..5a4c7250aa7 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1883,7 +1883,13 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
frame = (struct fip_frame *)skb->data;
memset(frame, 0, len);
memcpy(frame->eth.h_dest, dest, ETH_ALEN);
- memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+
+ if (sub == FIP_SC_VN_BEACON) {
+ hton24(frame->eth.h_source, FIP_VN_FC_MAP);
+ hton24(frame->eth.h_source + 3, fip->port_id);
+ } else {
+ memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+ }
frame->eth.h_proto = htons(ETH_P_FIP);
frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 500e20dd56e..796482badf1 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -159,6 +159,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev,
int qdepth, int reason);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
+static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
static int hpsa_slave_alloc(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
@@ -171,7 +172,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
static void calc_bucket_map(int *bucket, int num_buckets,
int nsgs, int *bucket_map);
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
-static inline u32 next_command(struct ctlr_info *h);
+static inline u32 next_command(struct ctlr_info *h, u8 q);
static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
u64 *cfg_offset);
@@ -180,6 +181,7 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
void __iomem *vaddr, int wait_for_ready);
+static inline void finish_cmd(struct CommandList *c);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
@@ -234,6 +236,16 @@ static int check_for_unit_attention(struct ctlr_info *h,
return 1;
}
+static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
+{
+ if (c->err_info->CommandStatus != CMD_TARGET_STATUS ||
+ (c->err_info->ScsiStatus != SAM_STAT_BUSY &&
+ c->err_info->ScsiStatus != SAM_STAT_TASK_SET_FULL))
+ return 0;
+ dev_warn(&h->pdev->dev, HPSA "device busy");
+ return 1;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -368,7 +380,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
}
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
- "UNKNOWN"
+ "1(ADM)", "UNKNOWN"
};
#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
@@ -497,6 +509,7 @@ static struct scsi_host_template hpsa_driver_template = {
.change_queue_depth = hpsa_change_queue_depth,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
+ .eh_abort_handler = hpsa_eh_abort_handler,
.eh_device_reset_handler = hpsa_eh_device_reset_handler,
.ioctl = hpsa_ioctl,
.slave_alloc = hpsa_slave_alloc,
@@ -516,24 +529,28 @@ static inline void addQ(struct list_head *list, struct CommandList *c)
list_add_tail(&c->list, list);
}
-static inline u32 next_command(struct ctlr_info *h)
+static inline u32 next_command(struct ctlr_info *h, u8 q)
{
u32 a;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags;
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
- return h->access.command_completed(h);
+ return h->access.command_completed(h, q);
- if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
- a = *(h->reply_pool_head); /* Next cmd in ring buffer */
- (h->reply_pool_head)++;
+ if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ a = rq->head[rq->current_entry];
+ rq->current_entry++;
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
} else {
a = FIFO_EMPTY;
}
/* Check for wraparound */
- if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
- h->reply_pool_head = h->reply_pool;
- h->reply_pool_wraparound ^= 1;
+ if (rq->current_entry == h->max_commands) {
+ rq->current_entry = 0;
+ rq->wraparound ^= 1;
}
return a;
}
@@ -544,8 +561,41 @@ static inline u32 next_command(struct ctlr_info *h)
*/
static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
{
- if (likely(h->transMethod & CFGTBL_Trans_Performant))
+ if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+ if (likely(h->msix_vector))
+ c->Header.ReplyQueue =
+ smp_processor_id() % h->nreply_queues;
+ }
+}
+
+static int is_firmware_flash_cmd(u8 *cdb)
+{
+ return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
+}
+
+/*
+ * During firmware flash, the heartbeat register may not update as frequently
+ * as it should. So we dial down lockup detection during firmware flash. and
+ * dial it back up when firmware flash completes.
+ */
+#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
+#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
+static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (!is_firmware_flash_cmd(c->Request.CDB))
+ return;
+ atomic_inc(&h->firmware_flash_in_progress);
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
+}
+
+static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (is_firmware_flash_cmd(c->Request.CDB) &&
+ atomic_dec_and_test(&h->firmware_flash_in_progress))
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
}
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
@@ -554,11 +604,12 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
unsigned long flags;
set_performant_mode(h, c);
+ dial_down_lockup_detection_during_fw_flash(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
h->Qdepth++;
- start_io(h);
spin_unlock_irqrestore(&h->lock, flags);
+ start_io(h);
}
static inline void removeQ(struct CommandList *c)
@@ -1193,7 +1244,7 @@ static void complete_scsi_command(struct CommandList *cp)
break;
}
/* Must be some other type of check condition */
- dev_warn(&h->pdev->dev, "cp %p has check condition: "
+ dev_dbg(&h->pdev->dev, "cp %p has check condition: "
"unknown type: "
"Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
"Returning result: 0x%x, "
@@ -1370,16 +1421,24 @@ static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h,
}
}
+#define MAX_DRIVER_CMD_RETRIES 25
static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
struct CommandList *c, int data_direction)
{
- int retry_count = 0;
+ int backoff_time = 10, retry_count = 0;
do {
memset(c->err_info, 0, sizeof(*c->err_info));
hpsa_scsi_do_simple_cmd_core(h, c);
retry_count++;
- } while (check_for_unit_attention(h, c) && retry_count <= 3);
+ if (retry_count > 3) {
+ msleep(backoff_time);
+ if (backoff_time < 1000)
+ backoff_time *= 2;
+ }
+ } while ((check_for_unit_attention(h, c) ||
+ check_for_busy(h, c)) &&
+ retry_count <= MAX_DRIVER_CMD_RETRIES);
hpsa_pci_unmap(h->pdev, c, 1, data_direction);
}
@@ -2065,9 +2124,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
done(cmd);
return 0;
}
- /* Need a lock as this is being allocated from the pool */
- c = cmd_alloc(h);
spin_unlock_irqrestore(&h->lock, flags);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2334,6 +2392,261 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
return FAILED;
}
+static void swizzle_abort_tag(u8 *tag)
+{
+ u8 original_tag[8];
+
+ memcpy(original_tag, tag, 8);
+ tag[0] = original_tag[3];
+ tag[1] = original_tag[2];
+ tag[2] = original_tag[1];
+ tag[3] = original_tag[0];
+ tag[4] = original_tag[7];
+ tag[5] = original_tag[6];
+ tag[6] = original_tag[5];
+ tag[7] = original_tag[4];
+}
+
+static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
+ struct CommandList *abort, int swizzle)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+
+ fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG);
+ if (swizzle)
+ swizzle_abort_tag(&c->Request.CDB[4]);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
+ __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
+ /* no unmap needed here because no data xfer. */
+
+ ei = c->err_info;
+ switch (ei->CommandStatus) {
+ case CMD_SUCCESS:
+ break;
+ case CMD_UNABORTABLE: /* Very common, don't make noise. */
+ rc = -1;
+ break;
+ default:
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
+ __func__, abort->Header.Tag.upper,
+ abort->Header.Tag.lower);
+ hpsa_scsi_interpret_error(c);
+ rc = -1;
+ break;
+ }
+ cmd_special_free(h, c);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
+ abort->Header.Tag.upper, abort->Header.Tag.lower);
+ return rc;
+}
+
+/*
+ * hpsa_find_cmd_in_queue
+ *
+ * Used to determine whether a command (find) is still present
+ * in queue_head. Optionally excludes the last element of queue_head.
+ *
+ * This is used to avoid unnecessary aborts. Commands in h->reqQ have
+ * not yet been submitted, and so can be aborted by the driver without
+ * sending an abort to the hardware.
+ *
+ * Returns pointer to command if found in queue, NULL otherwise.
+ */
+static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
+ struct scsi_cmnd *find, struct list_head *queue_head)
+{
+ unsigned long flags;
+ struct CommandList *c = NULL; /* ptr into cmpQ */
+
+ if (!find)
+ return 0;
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, queue_head, list) {
+ if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */
+ continue;
+ if (c->scsi_cmd == find) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return c;
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return NULL;
+}
+
+static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
+ u8 *tag, struct list_head *queue_head)
+{
+ unsigned long flags;
+ struct CommandList *c;
+
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, queue_head, list) {
+ if (memcmp(&c->Header.Tag, tag, 8) != 0)
+ continue;
+ spin_unlock_irqrestore(&h->lock, flags);
+ return c;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return NULL;
+}
+
+/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
+ * tell which kind we're dealing with, so we send the abort both ways. There
+ * shouldn't be any collisions between swizzled and unswizzled tags due to the
+ * way we construct our tags but we check anyway in case the assumptions which
+ * make this true someday become false.
+ */
+static int hpsa_send_abort_both_ways(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct CommandList *abort)
+{
+ u8 swizzled_tag[8];
+ struct CommandList *c;
+ int rc = 0, rc2 = 0;
+
+ /* we do not expect to find the swizzled tag in our queue, but
+ * check anyway just to be sure the assumptions which make this
+ * the case haven't become wrong.
+ */
+ memcpy(swizzled_tag, &abort->Request.CDB[4], 8);
+ swizzle_abort_tag(swizzled_tag);
+ c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ);
+ if (c != NULL) {
+ dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n");
+ return hpsa_send_abort(h, scsi3addr, abort, 0);
+ }
+ rc = hpsa_send_abort(h, scsi3addr, abort, 0);
+
+ /* if the command is still in our queue, we can't conclude that it was
+ * aborted (it might have just completed normally) but in any case
+ * we don't need to try to abort it another way.
+ */
+ c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ);
+ if (c)
+ rc2 = hpsa_send_abort(h, scsi3addr, abort, 1);
+ return rc && rc2;
+}
+
+/* Send an abort for the specified command.
+ * If the device and controller support it,
+ * send a task abort request.
+ */
+static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
+{
+
+ int i, rc;
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+ struct CommandList *abort; /* pointer to command to be aborted */
+ struct CommandList *found;
+ struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
+ char msg[256]; /* For debug messaging. */
+ int ml = 0;
+
+ /* Find the controller of the command to be aborted */
+ h = sdev_to_hba(sc->device);
+ if (WARN(h == NULL,
+ "ABORT REQUEST FAILED, Controller lookup failed.\n"))
+ return FAILED;
+
+ /* Check that controller supports some kind of task abort */
+ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) &&
+ !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
+ return FAILED;
+
+ memset(msg, 0, sizeof(msg));
+ ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%d ",
+ h->scsi_host->host_no, sc->device->channel,
+ sc->device->id, sc->device->lun);
+
+ /* Find the device of the command to be aborted */
+ dev = sc->device->hostdata;
+ if (!dev) {
+ dev_err(&h->pdev->dev, "%s FAILED, Device lookup failed.\n",
+ msg);
+ return FAILED;
+ }
+
+ /* Get SCSI command to be aborted */
+ abort = (struct CommandList *) sc->host_scribble;
+ if (abort == NULL) {
+ dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n",
+ msg);
+ return FAILED;
+ }
+
+ ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
+ abort->Header.Tag.upper, abort->Header.Tag.lower);
+ as = (struct scsi_cmnd *) abort->scsi_cmd;
+ if (as != NULL)
+ ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
+ as->cmnd[0], as->serial_number);
+ dev_dbg(&h->pdev->dev, "%s\n", msg);
+ dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n",
+ h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
+
+ /* Search reqQ to See if command is queued but not submitted,
+ * if so, complete the command with aborted status and remove
+ * it from the reqQ.
+ */
+ found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ);
+ if (found) {
+ found->err_info->CommandStatus = CMD_ABORTED;
+ finish_cmd(found);
+ dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n",
+ msg);
+ return SUCCESS;
+ }
+
+ /* not in reqQ, if also not in cmpQ, must have already completed */
+ found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
+ if (!found) {
+ dev_dbg(&h->pdev->dev, "%s Request FAILED (not known to driver).\n",
+ msg);
+ return SUCCESS;
+ }
+
+ /*
+ * Command is in flight, or possibly already completed
+ * by the firmware (but not to the scsi mid layer) but we can't
+ * distinguish which. Send the abort down.
+ */
+ rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort);
+ if (rc != 0) {
+ dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg);
+ dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n",
+ h->scsi_host->host_no,
+ dev->bus, dev->target, dev->lun);
+ return FAILED;
+ }
+ dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg);
+
+ /* If the abort(s) above completed and actually aborted the
+ * command, then the command to be aborted should already be
+ * completed. If not, wait around a bit more to see if they
+ * manage to complete normally.
+ */
+#define ABORT_COMPLETE_WAIT_SECS 30
+ for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
+ found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
+ if (!found)
+ return SUCCESS;
+ msleep(100);
+ }
+ dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
+ msg, ABORT_COMPLETE_WAIT_SECS);
+ return FAILED;
+}
+
+
/*
* For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
@@ -2346,14 +2659,21 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
int i;
union u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
+ unsigned long flags;
+ spin_lock_irqsave(&h->lock, flags);
do {
i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
- if (i == h->nr_cmds)
+ if (i == h->nr_cmds) {
+ spin_unlock_irqrestore(&h->lock, flags);
return NULL;
+ }
} while (test_and_set_bit
(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
+ h->nr_allocs++;
+ spin_unlock_irqrestore(&h->lock, flags);
+
c = h->cmd_pool + i;
memset(c, 0, sizeof(*c));
cmd_dma_handle = h->cmd_pool_dhandle
@@ -2362,7 +2682,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
memset(c->err_info, 0, sizeof(*c->err_info));
err_dma_handle = h->errinfo_pool_dhandle
+ i * sizeof(*c->err_info);
- h->nr_allocs++;
c->cmdindex = i;
@@ -2418,11 +2737,14 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
static void cmd_free(struct ctlr_info *h, struct CommandList *c)
{
int i;
+ unsigned long flags;
i = c - h->cmd_pool;
+ spin_lock_irqsave(&h->lock, flags);
clear_bit(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG));
h->nr_frees++;
+ spin_unlock_irqrestore(&h->lock, flags);
}
static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
@@ -2866,6 +3188,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
int cmd_type)
{
int pci_dir = XFER_NONE;
+ struct CommandList *a; /* for commands to be aborted */
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
@@ -2949,8 +3272,35 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[5] = 0x00;
c->Request.CDB[6] = 0x00;
c->Request.CDB[7] = 0x00;
+ break;
+ case HPSA_ABORT_MSG:
+ a = buff; /* point to command to be aborted */
+ dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n",
+ a->Header.Tag.upper, a->Header.Tag.lower,
+ c->Header.Tag.upper, c->Header.Tag.lower);
+ c->Request.CDBLen = 16;
+ c->Request.Type.Type = TYPE_MSG;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_WRITE;
+ c->Request.Timeout = 0; /* Don't time out */
+ c->Request.CDB[0] = HPSA_TASK_MANAGEMENT;
+ c->Request.CDB[1] = HPSA_TMF_ABORT_TASK;
+ c->Request.CDB[2] = 0x00; /* reserved */
+ c->Request.CDB[3] = 0x00; /* reserved */
+ /* Tag to abort goes in CDB[4]-CDB[11] */
+ c->Request.CDB[4] = a->Header.Tag.lower & 0xFF;
+ c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF;
+ c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF;
+ c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF;
+ c->Request.CDB[8] = a->Header.Tag.upper & 0xFF;
+ c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF;
+ c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF;
+ c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF;
+ c->Request.CDB[12] = 0x00; /* reserved */
+ c->Request.CDB[13] = 0x00; /* reserved */
+ c->Request.CDB[14] = 0x00; /* reserved */
+ c->Request.CDB[15] = 0x00; /* reserved */
break;
-
default:
dev_warn(&h->pdev->dev, "unknown message type %d\n",
cmd);
@@ -2998,7 +3348,9 @@ static void __iomem *remap_pci_mem(ulong base, ulong size)
static void start_io(struct ctlr_info *h)
{
struct CommandList *c;
+ unsigned long flags;
+ spin_lock_irqsave(&h->lock, flags);
while (!list_empty(&h->reqQ)) {
c = list_entry(h->reqQ.next, struct CommandList, list);
/* can't do anything if fifo is full */
@@ -3011,17 +3363,28 @@ static void start_io(struct ctlr_info *h)
removeQ(c);
h->Qdepth--;
- /* Tell the controller execute command */
- h->access.submit_command(h, c);
-
/* Put job onto the completed Q */
addQ(&h->cmpQ, c);
+
+ /* Must increment commands_outstanding before unlocking
+ * and submitting to avoid race checking for fifo full
+ * condition.
+ */
+ h->commands_outstanding++;
+ if (h->commands_outstanding > h->max_outstanding)
+ h->max_outstanding = h->commands_outstanding;
+
+ /* Tell the controller execute command */
+ spin_unlock_irqrestore(&h->lock, flags);
+ h->access.submit_command(h, c);
+ spin_lock_irqsave(&h->lock, flags);
}
+ spin_unlock_irqrestore(&h->lock, flags);
}
-static inline unsigned long get_next_completion(struct ctlr_info *h)
+static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q)
{
- return h->access.command_completed(h);
+ return h->access.command_completed(h, q);
}
static inline bool interrupt_pending(struct ctlr_info *h)
@@ -3045,9 +3408,14 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
return 0;
}
-static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
+static inline void finish_cmd(struct CommandList *c)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->h->lock, flags);
removeQ(c);
+ spin_unlock_irqrestore(&c->h->lock, flags);
+ dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
if (likely(c->cmd_type == CMD_SCSI))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
@@ -3075,36 +3443,38 @@ static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
}
/* process completion of an indexed ("direct lookup") command */
-static inline u32 process_indexed_cmd(struct ctlr_info *h,
+static inline void process_indexed_cmd(struct ctlr_info *h,
u32 raw_tag)
{
u32 tag_index;
struct CommandList *c;
tag_index = hpsa_tag_to_index(raw_tag);
- if (bad_tag(h, tag_index, raw_tag))
- return next_command(h);
- c = h->cmd_pool + tag_index;
- finish_cmd(c, raw_tag);
- return next_command(h);
+ if (!bad_tag(h, tag_index, raw_tag)) {
+ c = h->cmd_pool + tag_index;
+ finish_cmd(c);
+ }
}
/* process completion of a non-indexed command */
-static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
+static inline void process_nonindexed_cmd(struct ctlr_info *h,
u32 raw_tag)
{
u32 tag;
struct CommandList *c = NULL;
+ unsigned long flags;
tag = hpsa_tag_discard_error_bits(h, raw_tag);
+ spin_lock_irqsave(&h->lock, flags);
list_for_each_entry(c, &h->cmpQ, list) {
if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
- finish_cmd(c, raw_tag);
- return next_command(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+ finish_cmd(c);
+ return;
}
}
+ spin_unlock_irqrestore(&h->lock, flags);
bad_tag(h, h->nr_cmds + 1, raw_tag);
- return next_command(h);
}
/* Some controllers, like p400, will give us one interrupt
@@ -3126,10 +3496,20 @@ static int ignore_bogus_interrupt(struct ctlr_info *h)
return 1;
}
-static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id)
+/*
+ * Convert &h->q[x] (passed to interrupt handlers) back to h.
+ * Relies on (h-q[x] == x) being true for x such that
+ * 0 <= x < MAX_REPLY_QUEUES.
+ */
+static struct ctlr_info *queue_to_hba(u8 *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ return container_of((queue - *queue), struct ctlr_info, q[0]);
+}
+
+static irqreturn_t hpsa_intx_discard_completions(int irq, void *queue)
+{
+ struct ctlr_info *h = queue_to_hba(queue);
+ u8 q = *(u8 *) queue;
u32 raw_tag;
if (ignore_bogus_interrupt(h))
@@ -3137,74 +3517,68 @@ static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id)
if (interrupt_not_for_us(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
while (interrupt_pending(h)) {
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY)
- raw_tag = next_command(h);
+ raw_tag = next_command(h, q);
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id)
+static irqreturn_t hpsa_msix_discard_completions(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba(queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
if (ignore_bogus_interrupt(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY)
- raw_tag = next_command(h);
- spin_unlock_irqrestore(&h->lock, flags);
+ raw_tag = next_command(h, q);
return IRQ_HANDLED;
}
-static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba((u8 *) queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
if (interrupt_not_for_us(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
while (interrupt_pending(h)) {
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (hpsa_tag_contains_index(raw_tag))
- raw_tag = process_indexed_cmd(h, raw_tag);
+ if (likely(hpsa_tag_contains_index(raw_tag)))
+ process_indexed_cmd(h, raw_tag);
else
- raw_tag = process_nonindexed_cmd(h, raw_tag);
+ process_nonindexed_cmd(h, raw_tag);
+ raw_tag = next_command(h, q);
}
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_msi(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba(queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (hpsa_tag_contains_index(raw_tag))
- raw_tag = process_indexed_cmd(h, raw_tag);
+ if (likely(hpsa_tag_contains_index(raw_tag)))
+ process_indexed_cmd(h, raw_tag);
else
- raw_tag = process_nonindexed_cmd(h, raw_tag);
+ process_nonindexed_cmd(h, raw_tag);
+ raw_tag = next_command(h, q);
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
@@ -3638,10 +4012,13 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
{
#ifdef CONFIG_PCI_MSI
- int err;
- struct msix_entry hpsa_msix_entries[4] = { {0, 0}, {0, 1},
- {0, 2}, {0, 3}
- };
+ int err, i;
+ struct msix_entry hpsa_msix_entries[MAX_REPLY_QUEUES];
+
+ for (i = 0; i < MAX_REPLY_QUEUES; i++) {
+ hpsa_msix_entries[i].vector = 0;
+ hpsa_msix_entries[i].entry = i;
+ }
/* Some boards advertise MSI but don't really support it */
if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
@@ -3649,12 +4026,11 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
dev_info(&h->pdev->dev, "MSIX\n");
- err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries,
+ MAX_REPLY_QUEUES);
if (!err) {
- h->intr[0] = hpsa_msix_entries[0].vector;
- h->intr[1] = hpsa_msix_entries[1].vector;
- h->intr[2] = hpsa_msix_entries[2].vector;
- h->intr[3] = hpsa_msix_entries[3].vector;
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ h->intr[i] = hpsa_msix_entries[i].vector;
h->msix_vector = 1;
return;
}
@@ -3705,14 +4081,6 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
}
-static inline bool hpsa_board_disabled(struct pci_dev *pdev)
-{
- u16 command;
-
- (void) pci_read_config_word(pdev, PCI_COMMAND, &command);
- return ((command & PCI_COMMAND_MEMORY) == 0);
-}
-
static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar)
{
@@ -3838,14 +4206,14 @@ static void __devinit hpsa_find_board_params(struct ctlr_info *h)
h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
}
+
+ /* Find out what task management functions are supported and cache */
+ h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
}
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
{
- if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
- (readb(&h->cfgtable->Signature[1]) != 'I') ||
- (readb(&h->cfgtable->Signature[2]) != 'S') ||
- (readb(&h->cfgtable->Signature[3]) != 'S')) {
+ if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
return false;
}
@@ -3932,11 +4300,6 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
- if (hpsa_board_disabled(h->pdev)) {
- dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
- return -ENODEV;
- }
-
pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
@@ -3946,6 +4309,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
return err;
}
+ /* Enable bus mastering (pci_disable_device may disable this) */
+ pci_set_master(h->pdev);
+
err = pci_request_regions(h->pdev, HPSA);
if (err) {
dev_err(&h->pdev->dev,
@@ -3987,10 +4353,7 @@ err_out_free_res:
iounmap(h->cfgtable);
if (h->vaddr)
iounmap(h->vaddr);
- /*
- * Deliberately omit pci_disable_device(): it does something nasty to
- * Smart Array controllers that pci_enable_device does not undo
- */
+ pci_disable_device(h->pdev);
pci_release_regions(h->pdev);
return err;
}
@@ -4081,14 +4444,33 @@ static int hpsa_request_irq(struct ctlr_info *h,
irqreturn_t (*msixhandler)(int, void *),
irqreturn_t (*intxhandler)(int, void *))
{
- int rc;
+ int rc, i;
- if (h->msix_vector || h->msi_vector)
- rc = request_irq(h->intr[h->intr_mode], msixhandler,
- 0, h->devname, h);
- else
- rc = request_irq(h->intr[h->intr_mode], intxhandler,
- IRQF_SHARED, h->devname, h);
+ /*
+ * initialize h->q[x] = x so that interrupt handlers know which
+ * queue to process.
+ */
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ h->q[i] = (u8) i;
+
+ if (h->intr_mode == PERF_MODE_INT && h->msix_vector) {
+ /* If performant mode and MSI-X, use multiple reply queues */
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ rc = request_irq(h->intr[i], msixhandler,
+ 0, h->devname,
+ &h->q[i]);
+ } else {
+ /* Use single reply pool */
+ if (h->msix_vector || h->msi_vector) {
+ rc = request_irq(h->intr[h->intr_mode],
+ msixhandler, 0, h->devname,
+ &h->q[h->intr_mode]);
+ } else {
+ rc = request_irq(h->intr[h->intr_mode],
+ intxhandler, IRQF_SHARED, h->devname,
+ &h->q[h->intr_mode]);
+ }
+ }
if (rc) {
dev_err(&h->pdev->dev, "unable to get irq %d for %s\n",
h->intr[h->intr_mode], h->devname);
@@ -4121,15 +4503,38 @@ static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h)
return 0;
}
-static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
+static void free_irqs(struct ctlr_info *h)
{
- free_irq(h->intr[h->intr_mode], h);
+ int i;
+
+ if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) {
+ /* Single reply queue, only one irq to free */
+ i = h->intr_mode;
+ free_irq(h->intr[i], &h->q[i]);
+ return;
+ }
+
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ free_irq(h->intr[i], &h->q[i]);
+}
+
+static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h)
+{
+ free_irqs(h);
#ifdef CONFIG_PCI_MSI
- if (h->msix_vector)
- pci_disable_msix(h->pdev);
- else if (h->msi_vector)
- pci_disable_msi(h->pdev);
+ if (h->msix_vector) {
+ if (h->pdev->msix_enabled)
+ pci_disable_msix(h->pdev);
+ } else if (h->msi_vector) {
+ if (h->pdev->msi_enabled)
+ pci_disable_msi(h->pdev);
+ }
#endif /* CONFIG_PCI_MSI */
+}
+
+static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
+{
+ hpsa_free_irqs_and_disable_msix(h);
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
kfree(h->blockFetchTable);
@@ -4165,7 +4570,7 @@ static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)
while (!list_empty(list)) {
c = list_entry(list->next, struct CommandList, list);
c->err_info->CommandStatus = CMD_HARDWARE_ERR;
- finish_cmd(c, c->Header.Tag.lower);
+ finish_cmd(c);
}
}
@@ -4188,9 +4593,6 @@ static void controller_lockup_detected(struct ctlr_info *h)
spin_unlock_irqrestore(&h->lock, flags);
}
-#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ)
-#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2)
-
static void detect_controller_lockup(struct ctlr_info *h)
{
u64 now;
@@ -4201,7 +4603,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
now = get_jiffies_64();
/* If we've received an interrupt recently, we're ok. */
if (time_after64(h->last_intr_timestamp +
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+ (h->heartbeat_sample_interval), now))
return;
/*
@@ -4210,7 +4612,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
* otherwise don't care about signals in this thread.
*/
if (time_after64(h->last_heartbeat_timestamp +
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+ (h->heartbeat_sample_interval), now))
return;
/* If heartbeat has not changed since we last looked, we're not ok. */
@@ -4252,6 +4654,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h)
{
unsigned long flags;
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
spin_lock_irqsave(&lockup_detector_lock, flags);
list_add_tail(&h->lockup_list, &hpsa_ctlr_list);
spin_unlock_irqrestore(&lockup_detector_lock, flags);
@@ -4391,7 +4794,7 @@ reinit_after_soft_reset:
spin_lock_irqsave(&h->lock, flags);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags);
- free_irq(h->intr[h->intr_mode], h);
+ free_irqs(h);
rc = hpsa_request_irq(h, hpsa_msix_discard_completions,
hpsa_intx_discard_completions);
if (rc) {
@@ -4441,7 +4844,7 @@ reinit_after_soft_reset:
clean4:
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
- free_irq(h->intr[h->intr_mode], h);
+ free_irqs(h);
clean2:
clean1:
kfree(h);
@@ -4484,13 +4887,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
*/
hpsa_flush_cache(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- free_irq(h->intr[h->intr_mode], h);
-#ifdef CONFIG_PCI_MSI
- if (h->msix_vector)
- pci_disable_msix(h->pdev);
- else if (h->msi_vector)
- pci_disable_msi(h->pdev);
-#endif /* CONFIG_PCI_MSI */
+ hpsa_free_irqs_and_disable_msix(h);
}
static void __devexit hpsa_free_device_info(struct ctlr_info *h)
@@ -4529,10 +4926,7 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
kfree(h->hba_inquiry_data);
- /*
- * Deliberately omit pci_disable_device(): it does something nasty to
- * Smart Array controllers that pci_enable_device does not undo
- */
+ pci_disable_device(pdev);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
kfree(h);
@@ -4627,11 +5021,8 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
* 10 = 6 s/g entry or 24k
*/
- h->reply_pool_wraparound = 1; /* spec: init to 1 */
-
/* Controller spec: zero out this buffer. */
memset(h->reply_pool, 0, h->reply_pool_size);
- h->reply_pool_head = h->reply_pool;
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
@@ -4641,12 +5032,19 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
/* size of controller ring buffer */
writel(h->max_commands, &h->transtable->RepQSize);
- writel(1, &h->transtable->RepQCount);
+ writel(h->nreply_queues, &h->transtable->RepQCount);
writel(0, &h->transtable->RepQCtrAddrLow32);
writel(0, &h->transtable->RepQCtrAddrHigh32);
- writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
- writel(0, &h->transtable->RepQAddr0High32);
- writel(CFGTBL_Trans_Performant | use_short_tags,
+
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(0, &h->transtable->RepQAddr[i].upper);
+ writel(h->reply_pool_dhandle +
+ (h->max_commands * sizeof(u64) * i),
+ &h->transtable->RepQAddr[i].lower);
+ }
+
+ writel(CFGTBL_Trans_Performant | use_short_tags |
+ CFGTBL_Trans_enable_directed_msix,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
@@ -4664,6 +5062,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
+ int i;
if (hpsa_simple_mode)
return;
@@ -4672,12 +5071,20 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
if (!(trans_support & PERFORMANT_MODE))
return;
+ h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1;
hpsa_get_max_perf_mode_cmds(h);
/* Performant mode ring buffer and supporting data structures */
- h->reply_pool_size = h->max_commands * sizeof(u64);
+ h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues;
h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
&(h->reply_pool_dhandle));
+ for (i = 0; i < h->nreply_queues; i++) {
+ h->reply_queue[i].head = &h->reply_pool[h->max_commands * i];
+ h->reply_queue[i].size = h->max_commands;
+ h->reply_queue[i].wraparound = 1; /* spec: init to 1 */
+ h->reply_queue[i].current_entry = 0;
+ }
+
/* Need a block fetch table for performant mode */
h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *
sizeof(u32)), GFP_KERNEL);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 7b28d54fa87..981647989bf 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -34,7 +34,7 @@ struct access_method {
void (*set_intr_mask)(struct ctlr_info *h, unsigned long val);
unsigned long (*fifo_full)(struct ctlr_info *h);
bool (*intr_pending)(struct ctlr_info *h);
- unsigned long (*command_completed)(struct ctlr_info *h);
+ unsigned long (*command_completed)(struct ctlr_info *h, u8 q);
};
struct hpsa_scsi_dev_t {
@@ -48,6 +48,13 @@ struct hpsa_scsi_dev_t {
unsigned char raid_level; /* from inquiry page 0xC1 */
};
+struct reply_pool {
+ u64 *head;
+ size_t size;
+ u8 wraparound;
+ u32 current_entry;
+};
+
struct ctlr_info {
int ctlr;
char devname[8];
@@ -68,7 +75,7 @@ struct ctlr_info {
# define DOORBELL_INT 1
# define SIMPLE_MODE_INT 2
# define MEMQ_MODE_INT 3
- unsigned int intr[4];
+ unsigned int intr[MAX_REPLY_QUEUES];
unsigned int msix_vector;
unsigned int msi_vector;
int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
@@ -78,7 +85,6 @@ struct ctlr_info {
struct list_head reqQ;
struct list_head cmpQ;
unsigned int Qdepth;
- unsigned int maxQsinceinit;
unsigned int maxSG;
spinlock_t lock;
int maxsgentries;
@@ -111,20 +117,45 @@ struct ctlr_info {
unsigned long transMethod;
/*
- * Performant mode completion buffer
+ * Performant mode completion buffers
*/
u64 *reply_pool;
- dma_addr_t reply_pool_dhandle;
- u64 *reply_pool_head;
size_t reply_pool_size;
- unsigned char reply_pool_wraparound;
+ struct reply_pool reply_queue[MAX_REPLY_QUEUES];
+ u8 nreply_queues;
+ dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
unsigned char *hba_inquiry_data;
u64 last_intr_timestamp;
u32 last_heartbeat;
u64 last_heartbeat_timestamp;
+ u32 heartbeat_sample_interval;
+ atomic_t firmware_flash_in_progress;
u32 lockup_detected;
struct list_head lockup_list;
+ /* Address of h->q[x] is passed to intr handler to know which queue */
+ u8 q[MAX_REPLY_QUEUES];
+ u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */
+#define HPSATMF_BITS_SUPPORTED (1 << 0)
+#define HPSATMF_PHYS_LUN_RESET (1 << 1)
+#define HPSATMF_PHYS_NEX_RESET (1 << 2)
+#define HPSATMF_PHYS_TASK_ABORT (1 << 3)
+#define HPSATMF_PHYS_TSET_ABORT (1 << 4)
+#define HPSATMF_PHYS_CLEAR_ACA (1 << 5)
+#define HPSATMF_PHYS_CLEAR_TSET (1 << 6)
+#define HPSATMF_PHYS_QRY_TASK (1 << 7)
+#define HPSATMF_PHYS_QRY_TSET (1 << 8)
+#define HPSATMF_PHYS_QRY_ASYNC (1 << 9)
+#define HPSATMF_MASK_SUPPORTED (1 << 16)
+#define HPSATMF_LOG_LUN_RESET (1 << 17)
+#define HPSATMF_LOG_NEX_RESET (1 << 18)
+#define HPSATMF_LOG_TASK_ABORT (1 << 19)
+#define HPSATMF_LOG_TSET_ABORT (1 << 20)
+#define HPSATMF_LOG_CLEAR_ACA (1 << 21)
+#define HPSATMF_LOG_CLEAR_TSET (1 << 22)
+#define HPSATMF_LOG_QRY_TASK (1 << 23)
+#define HPSATMF_LOG_QRY_TSET (1 << 24)
+#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
@@ -216,9 +247,6 @@ static void SA5_submit_command(struct ctlr_info *h,
c->Header.Tag.lower);
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
- h->commands_outstanding++;
- if (h->commands_outstanding > h->max_outstanding)
- h->max_outstanding = h->commands_outstanding;
}
/*
@@ -254,16 +282,17 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)
}
}
-static unsigned long SA5_performant_completed(struct ctlr_info *h)
+static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
{
- unsigned long register_value = FIFO_EMPTY;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags, register_value = FIFO_EMPTY;
- /* flush the controller write of the reply queue by reading
- * outbound doorbell status register.
- */
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
/* msi auto clears the interrupt pending bit. */
if (!(h->msi_vector || h->msix_vector)) {
+ /* flush the controller write of the reply queue by reading
+ * outbound doorbell status register.
+ */
+ register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
/* Do a read in order to flush the write to the controller
* (as per spec.)
@@ -271,19 +300,20 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h)
register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
}
- if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
- register_value = *(h->reply_pool_head);
- (h->reply_pool_head)++;
+ if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ register_value = rq->head[rq->current_entry];
+ rq->current_entry++;
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
} else {
register_value = FIFO_EMPTY;
}
/* Check for wraparound */
- if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
- h->reply_pool_head = h->reply_pool;
- h->reply_pool_wraparound ^= 1;
+ if (rq->current_entry == h->max_commands) {
+ rq->current_entry = 0;
+ rq->wraparound ^= 1;
}
-
return register_value;
}
@@ -303,13 +333,18 @@ static unsigned long SA5_fifo_full(struct ctlr_info *h)
* returns value read from hardware.
* returns FIFO_EMPTY if there is nothing to read
*/
-static unsigned long SA5_completed(struct ctlr_info *h)
+static unsigned long SA5_completed(struct ctlr_info *h,
+ __attribute__((unused)) u8 q)
{
unsigned long register_value
= readl(h->vaddr + SA5_REPLY_PORT_OFFSET);
+ unsigned long flags;
- if (register_value != FIFO_EMPTY)
+ if (register_value != FIFO_EMPTY) {
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
+ }
#ifdef HPSA_DEBUG
if (register_value != FIFO_EMPTY)
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 8049815d8c1..a894f2eca7a 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -82,6 +82,29 @@
#define TYPE_CMD 0x00
#define TYPE_MSG 0x01
+/* Message Types */
+#define HPSA_TASK_MANAGEMENT 0x00
+#define HPSA_RESET 0x01
+#define HPSA_SCAN 0x02
+#define HPSA_NOOP 0x03
+
+#define HPSA_CTLR_RESET_TYPE 0x00
+#define HPSA_BUS_RESET_TYPE 0x01
+#define HPSA_TARGET_RESET_TYPE 0x03
+#define HPSA_LUN_RESET_TYPE 0x04
+#define HPSA_NEXUS_RESET_TYPE 0x05
+
+/* Task Management Functions */
+#define HPSA_TMF_ABORT_TASK 0x00
+#define HPSA_TMF_ABORT_TASK_SET 0x01
+#define HPSA_TMF_CLEAR_ACA 0x02
+#define HPSA_TMF_CLEAR_TASK_SET 0x03
+#define HPSA_TMF_QUERY_TASK 0x04
+#define HPSA_TMF_QUERY_TASK_SET 0x05
+#define HPSA_TMF_QUERY_ASYNCEVENT 0x06
+
+
+
/* config space register offsets */
#define CFG_VENDORID 0x00
#define CFG_DEVICEID 0x02
@@ -106,6 +129,7 @@
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
#define CFGTBL_Trans_use_short_tags 0x20000000l
+#define CFGTBL_Trans_enable_directed_msix (1 << 30)
#define CFGTBL_BusType_Ultra2 0x00000001l
#define CFGTBL_BusType_Ultra3 0x00000002l
@@ -162,6 +186,7 @@ struct SenseSubsystem_info {
#define BMIC_WRITE 0x27
#define BMIC_CACHE_FLUSH 0xc2
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
+#define BMIC_FLASH_FIRMWARE 0xF7
/* Command List Structure */
union SCSI3Addr {
@@ -337,11 +362,17 @@ struct CfgTable {
u32 MaxPhysicalDevices;
u32 MaxPhysicalDrivesPerLogicalUnit;
u32 MaxPerformantModeCommands;
- u8 reserved[0x78 - 0x58];
+ u32 MaxBlockFetch;
+ u32 PowerConservationSupport;
+ u32 PowerConservationEnable;
+ u32 TMFSupportFlags;
+ u8 TMFTagMask[8];
+ u8 reserved[0x78 - 0x70];
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
#define MISC_FW_DOORBELL_RESET2 (0x010)
u8 driver_version[32];
+
};
#define NUM_BLOCKFETCH_ENTRIES 8
@@ -351,8 +382,8 @@ struct TransTable_struct {
u32 RepQCount;
u32 RepQCtrAddrLow32;
u32 RepQCtrAddrHigh32;
- u32 RepQAddr0Low32;
- u32 RepQAddr0High32;
+#define MAX_REPLY_QUEUES 8
+ struct vals32 RepQAddr[MAX_REPLY_QUEUES];
};
struct hpsa_pci_info {
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index cc83b66d45b..c1402fb499a 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -648,6 +648,7 @@ int fc_lport_destroy(struct fc_lport *lport)
lport->tt.fcp_abort_io(lport);
lport->tt.disc_stop_final(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
+ cancel_delayed_work_sync(&lport->retry_work);
fc_fc4_del_lport(lport);
return 0;
}
@@ -1564,7 +1565,6 @@ static void fc_lport_timeout(struct work_struct *work)
switch (lport->state) {
case LPORT_ST_DISABLED:
- WARN_ON(1);
break;
case LPORT_ST_READY:
break;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3a1ffdd6d83..e5da6da20f8 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -93,6 +93,9 @@ struct lpfc_sli2_slim;
/* lpfc wait event data ready flag */
#define LPFC_DATA_READY (1<<0)
+/* queue dump line buffer size */
+#define LPFC_LBUF_SZ 128
+
enum lpfc_polling_flags {
ENABLE_FCP_RING_POLLING = 0x1,
DISABLE_FCP_RING_INT = 0x2
@@ -620,6 +623,7 @@ struct lpfc_hba {
#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
+#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 141e4b40bb5..253d9a85734 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2009-2011 Emulex. All rights reserved. *
+ * Copyright (C) 2009-2012 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -599,6 +599,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
cmdiocbq->context1 = dd_data;
+ cmdiocbq->context_un.ndlp = ndlp;
cmdiocbq->context2 = rspiocbq;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
@@ -3978,6 +3979,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
} else if (subsys == SLI_CONFIG_SUBSYS_COMN) {
switch (opcode) {
case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
+ case COMN_OPCODE_GET_CNTL_ATTRIBUTES:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3106 Handled SLI_CONFIG "
"subsys_comn, opcode:x%x\n",
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index edfe61fc52b..67f7d0a160d 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2010 Emulex. All rights reserved. *
+ * Copyright (C) 2010-2012 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -249,6 +249,7 @@ struct lpfc_sli_config_emb1_subsys {
#define COMN_OPCODE_READ_OBJECT_LIST 0xAD
#define COMN_OPCODE_DELETE_OBJECT 0xAE
#define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79
+#define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20
uint32_t timeout;
uint32_t request_length;
uint32_t word9;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 330dd7192a7..9b2a16f3bc7 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -254,6 +254,7 @@ int
lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
+struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -460,6 +461,7 @@ int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t);
int lpfc_issue_reg_vfi(struct lpfc_vport *);
int lpfc_issue_unreg_vfi(struct lpfc_vport *);
int lpfc_selective_reset(struct lpfc_hba *);
-int lpfc_sli4_read_config(struct lpfc_hba *phba);
-int lpfc_scsi_buf_update(struct lpfc_hba *phba);
-void lpfc_sli4_node_prep(struct lpfc_hba *phba);
+int lpfc_sli4_read_config(struct lpfc_hba *);
+void lpfc_sli4_node_prep(struct lpfc_hba *);
+int lpfc_sli4_xri_sgl_update(struct lpfc_hba *);
+void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index af04b0d6688..3217d63ed28 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -4466,3 +4466,49 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
#endif
return;
}
+
+/*
+ * Driver debug utility routines outside of debugfs. The debug utility
+ * routines implemented here is intended to be used in the instrumented
+ * debug driver for debugging host or port issues.
+ */
+
+/**
+ * lpfc_debug_dump_all_queues - dump all the queues with a hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps entries of all the queues asociated with the @phba.
+ **/
+void
+lpfc_debug_dump_all_queues(struct lpfc_hba *phba)
+{
+ int fcp_wqidx;
+
+ /*
+ * Dump Work Queues (WQs)
+ */
+ lpfc_debug_dump_mbx_wq(phba);
+ lpfc_debug_dump_els_wq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_wq(phba, fcp_wqidx);
+
+ lpfc_debug_dump_hdr_rq(phba);
+ lpfc_debug_dump_dat_rq(phba);
+ /*
+ * Dump Complete Queues (CQs)
+ */
+ lpfc_debug_dump_mbx_cq(phba);
+ lpfc_debug_dump_els_cq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_cq(phba, fcp_wqidx);
+
+ /*
+ * Dump Event Queues (EQs)
+ */
+ lpfc_debug_dump_sp_eq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_eq(phba, fcp_wqidx);
+}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index f83bd944edd..616c400dae1 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -267,3 +267,421 @@ struct lpfc_idiag {
#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general
* discovery */
#endif /* H_LPFC_DEBUG_FS */
+
+
+/*
+ * Driver debug utility routines outside of debugfs. The debug utility
+ * routines implemented here is intended to be used in the instrumented
+ * debug driver for debugging host or port issues.
+ */
+
+/**
+ * lpfc_debug_dump_qe - dump an specific entry from a queue
+ * @q: Pointer to the queue descriptor.
+ * @idx: Index to the entry on the queue.
+ *
+ * This function dumps an entry indexed by @idx from a queue specified by the
+ * queue descriptor @q.
+ **/
+static inline void
+lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx)
+{
+ char line_buf[LPFC_LBUF_SZ];
+ int i, esize, qe_word_cnt, len;
+ uint32_t *pword;
+
+ /* sanity checks */
+ if (!q)
+ return;
+ if (idx >= q->entry_count)
+ return;
+
+ esize = q->entry_size;
+ qe_word_cnt = esize / sizeof(uint32_t);
+ pword = q->qe[idx].address;
+
+ len = 0;
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx);
+ if (qe_word_cnt > 8)
+ printk(KERN_ERR "%s\n", line_buf);
+
+ for (i = 0; i < qe_word_cnt; i++) {
+ if (!(i % 8)) {
+ if (i != 0)
+ printk(KERN_ERR "%s\n", line_buf);
+ if (qe_word_cnt > 8) {
+ len = 0;
+ memset(line_buf, 0, LPFC_LBUF_SZ);
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len,
+ "%03d: ", i);
+ }
+ }
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ",
+ ((uint32_t)*pword) & 0xffffffff);
+ pword++;
+ }
+ if (qe_word_cnt <= 8 || (i - 1) % 8)
+ printk(KERN_ERR "%s\n", line_buf);
+}
+
+/**
+ * lpfc_debug_dump_q - dump all entries from an specific queue
+ * @q: Pointer to the queue descriptor.
+ *
+ * This function dumps all entries from a queue specified by the queue
+ * descriptor @q.
+ **/
+static inline void
+lpfc_debug_dump_q(struct lpfc_queue *q)
+{
+ int idx, entry_count;
+
+ /* sanity check */
+ if (!q)
+ return;
+
+ dev_printk(KERN_ERR, &(((q->phba))->pcidev)->dev,
+ "%d: [qid:%d, type:%d, subtype:%d, "
+ "qe_size:%d, qe_count:%d, "
+ "host_index:%d, port_index:%d]\n",
+ (q->phba)->brd_no,
+ q->queue_id, q->type, q->subtype,
+ q->entry_size, q->entry_count,
+ q->host_index, q->hba_index);
+ entry_count = q->entry_count;
+ for (idx = 0; idx < entry_count; idx++)
+ lpfc_debug_dump_qe(q, idx);
+ printk(KERN_ERR "\n");
+}
+
+/**
+ * lpfc_debug_dump_fcp_wq - dump all entries from a fcp work queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP work queue specified by the
+ * @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_wq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+
+ printk(KERN_ERR "FCP WQ: WQ[Idx:%d|Qid:%d]\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[fcp_wqidx]);
+}
+
+/**
+ * lpfc_debug_dump_fcp_cq - dump all entries from a fcp work queue's cmpl queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP complete queue which is
+ * associated to the FCP work queue specified by the @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ int fcp_cqidx, fcp_cqid;
+
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+
+ fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid;
+ for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
+ if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
+ break;
+ if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+ return;
+
+ printk(KERN_ERR "FCP CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]:\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+ fcp_cqidx, fcp_cqid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[fcp_cqidx]);
+}
+
+/**
+ * lpfc_debug_dump_fcp_eq - dump all entries from a fcp work queue's evt queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP event queue which is
+ * associated to the FCP work queue specified by the @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ struct lpfc_queue *qdesc;
+ int fcp_eqidx, fcp_eqid;
+ int fcp_cqidx, fcp_cqid;
+
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+ fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid;
+ for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
+ if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
+ break;
+ if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+ return;
+
+ if (phba->cfg_fcp_eq_count == 0) {
+ fcp_eqidx = -1;
+ fcp_eqid = phba->sli4_hba.sp_eq->queue_id;
+ qdesc = phba->sli4_hba.sp_eq;
+ } else {
+ fcp_eqidx = fcp_cqidx;
+ fcp_eqid = phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id;
+ qdesc = phba->sli4_hba.fp_eq[fcp_eqidx];
+ }
+
+ printk(KERN_ERR "FCP EQ: WQ[Idx:%d|Qid:%d]->CQ[Idx:%d|Qid:%d]->"
+ "EQ[Idx:%d|Qid:%d]\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+ fcp_cqidx, fcp_cqid, fcp_eqidx, fcp_eqid);
+ lpfc_debug_dump_q(qdesc);
+}
+
+/**
+ * lpfc_debug_dump_els_wq - dump all entries from the els work queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the ELS work queue.
+ **/
+static inline void
+lpfc_debug_dump_els_wq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "ELS WQ: WQ[Qid:%d]:\n",
+ phba->sli4_hba.els_wq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.els_wq);
+}
+
+/**
+ * lpfc_debug_dump_mbx_wq - dump all entries from the mbox work queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the MBOX work queue.
+ **/
+static inline void
+lpfc_debug_dump_mbx_wq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "MBX WQ: WQ[Qid:%d]\n",
+ phba->sli4_hba.mbx_wq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_wq);
+}
+
+/**
+ * lpfc_debug_dump_dat_rq - dump all entries from the receive data queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the receive data queue.
+ **/
+static inline void
+lpfc_debug_dump_dat_rq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "DAT RQ: RQ[Qid:%d]\n",
+ phba->sli4_hba.dat_rq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.dat_rq);
+}
+
+/**
+ * lpfc_debug_dump_hdr_rq - dump all entries from the receive header queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the receive header queue.
+ **/
+static inline void
+lpfc_debug_dump_hdr_rq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "HDR RQ: RQ[Qid:%d]\n",
+ phba->sli4_hba.hdr_rq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.hdr_rq);
+}
+
+/**
+ * lpfc_debug_dump_els_cq - dump all entries from the els complete queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the els complete queue.
+ **/
+static inline void
+lpfc_debug_dump_els_cq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "ELS CQ: WQ[Qid:%d]->CQ[Qid:%d]\n",
+ phba->sli4_hba.els_wq->queue_id,
+ phba->sli4_hba.els_cq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.els_cq);
+}
+
+/**
+ * lpfc_debug_dump_mbx_cq - dump all entries from the mbox complete queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the mbox complete queue.
+ **/
+static inline void
+lpfc_debug_dump_mbx_cq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "MBX CQ: WQ[Qid:%d]->CQ[Qid:%d]\n",
+ phba->sli4_hba.mbx_wq->queue_id,
+ phba->sli4_hba.mbx_cq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_cq);
+}
+
+/**
+ * lpfc_debug_dump_sp_eq - dump all entries from slow-path event queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the slow-path event queue.
+ **/
+static inline void
+lpfc_debug_dump_sp_eq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "SP EQ: WQ[Qid:%d/Qid:%d]->CQ[Qid:%d/Qid:%d]->"
+ "EQ[Qid:%d]:\n",
+ phba->sli4_hba.mbx_wq->queue_id,
+ phba->sli4_hba.els_wq->queue_id,
+ phba->sli4_hba.mbx_cq->queue_id,
+ phba->sli4_hba.els_cq->queue_id,
+ phba->sli4_hba.sp_eq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.sp_eq);
+}
+
+/**
+ * lpfc_debug_dump_wq_by_id - dump all entries from a work queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Work queue identifier.
+ *
+ * This function dumps all entries from a work queue identified by the queue
+ * identifier.
+ **/
+static inline void
+lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int wq_idx;
+
+ for (wq_idx = 0; wq_idx < phba->cfg_fcp_wq_count; wq_idx++)
+ if (phba->sli4_hba.fcp_wq[wq_idx]->queue_id == qid)
+ break;
+ if (wq_idx < phba->cfg_fcp_wq_count) {
+ printk(KERN_ERR "FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[wq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.els_wq->queue_id == qid) {
+ printk(KERN_ERR "ELS WQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.els_wq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_mq_by_id - dump all entries from a mbox queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Mbox work queue identifier.
+ *
+ * This function dumps all entries from a mbox work queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_mq_by_id(struct lpfc_hba *phba, int qid)
+{
+ if (phba->sli4_hba.mbx_wq->queue_id == qid) {
+ printk(KERN_ERR "MBX WQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_wq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_rq_by_id - dump all entries from a receive queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Receive queue identifier.
+ *
+ * This function dumps all entries from a receive queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_rq_by_id(struct lpfc_hba *phba, int qid)
+{
+ if (phba->sli4_hba.hdr_rq->queue_id == qid) {
+ printk(KERN_ERR "HDR RQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.hdr_rq);
+ return;
+ }
+ if (phba->sli4_hba.dat_rq->queue_id == qid) {
+ printk(KERN_ERR "DAT RQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.dat_rq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_cq_by_id - dump all entries from a cmpl queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Complete queue identifier.
+ *
+ * This function dumps all entries from a complete queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int cq_idx = 0;
+
+ do {
+ if (phba->sli4_hba.fcp_cq[cq_idx]->queue_id == qid)
+ break;
+ } while (++cq_idx < phba->cfg_fcp_eq_count);
+
+ if (cq_idx < phba->cfg_fcp_eq_count) {
+ printk(KERN_ERR "FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[cq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.els_cq->queue_id == qid) {
+ printk(KERN_ERR "ELS CQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.els_cq);
+ return;
+ }
+
+ if (phba->sli4_hba.mbx_cq->queue_id == qid) {
+ printk(KERN_ERR "MBX CQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_cq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_eq_by_id - dump all entries from an event queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Complete queue identifier.
+ *
+ * This function dumps all entries from an event queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_eq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int eq_idx;
+
+ for (eq_idx = 0; eq_idx < phba->cfg_fcp_eq_count; eq_idx++) {
+ if (phba->sli4_hba.fp_eq[eq_idx]->queue_id == qid)
+ break;
+ }
+
+ if (eq_idx < phba->cfg_fcp_eq_count) {
+ printk(KERN_ERR "FCP EQ[Idx:%d|Qid:%d]\n", eq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fp_eq[eq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.sp_eq->queue_id == qid) {
+ printk(KERN_ERR "SP EQ[|Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.sp_eq);
+ }
+}
+
+void lpfc_debug_dump_all_queues(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 3407b39e0a3..d54ae199979 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -230,27 +230,43 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
INIT_LIST_HEAD(&pbuflist->list);
- icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
- icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
- icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
- icmd->un.elsreq64.remoteID = did; /* DID */
if (expectRsp) {
+ icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
+ icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
+ icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
+
+ icmd->un.elsreq64.remoteID = did; /* DID */
icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
icmd->ulpTimeout = phba->fc_ratov * 2;
} else {
- icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
+ icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
+ icmd->un.xseq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
+ icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ icmd->un.xseq64.bdl.bdeSize = sizeof(struct ulp_bde64);
+ icmd->un.xseq64.xmit_els_remoteID = did; /* DID */
icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
}
icmd->ulpBdeCount = 1;
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
- if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
- icmd->un.elsreq64.myID = vport->fc_myDID;
+ /*
+ * If we have NPIV enabled, we want to send ELS traffic by VPI.
+ * For SLI4, since the driver controls VPIs we also want to include
+ * all ELS pt2pt protocol traffic as well.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) ||
+ ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (vport->fc_flag & FC_PT2PT))) {
+
+ if (expectRsp) {
+ icmd->un.elsreq64.myID = vport->fc_myDID;
+
+ /* For ELS_REQUEST64_CR, use the VPI by default */
+ icmd->ulpContext = phba->vpi_ids[vport->vpi];
+ }
- /* For ELS_REQUEST64_CR, use the VPI by default */
- icmd->ulpContext = phba->vpi_ids[vport->vpi];
icmd->ulpCt_h = 0;
/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
if (elscmd == ELS_CMD_ECHO)
@@ -438,9 +454,10 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
int rc = 0;
sp = &phba->fc_fabparam;
- /* move forward in case of SLI4 FC port loopback test */
+ /* move forward in case of SLI4 FC port loopback test and pt2pt mode */
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- !(phba->link_flag & LS_LOOPBACK_MODE)) {
+ !(phba->link_flag & LS_LOOPBACK_MODE) &&
+ !(vport->fc_flag & FC_PT2PT)) {
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
rc = -ENODEV;
@@ -707,14 +724,17 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- /*
- * If VPI is unreged, driver need to do INIT_VPI
- * before re-registering
- */
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
+
+ /*
+ * For SLI3 and SLI4, the VPI needs to be reregistered in
+ * response to this fabric parameter change event.
+ */
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
} else if ((phba->sli_rev == LPFC_SLI_REV4) &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/*
@@ -817,6 +837,17 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
+
+ /*
+ * For SLI4, the VFI/VPI are registered AFTER the
+ * Nport with the higher WWPN sends the PLOGI with
+ * an assigned NPortId.
+ */
+
+ /* not equal */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
+ lpfc_issue_reg_vfi(vport);
+
/* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done.
*/
@@ -2972,7 +3003,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* ABTS we cannot generate and RRQ.
*/
lpfc_set_rrq_active(phba, ndlp,
- cmdiocb->sli4_xritag, 0, 0);
+ cmdiocb->sli4_lxritag, 0, 0);
}
break;
case IOSTAT_LOCAL_REJECT:
@@ -3803,10 +3834,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
- "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+ "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x "
+ "fc_flag x%x\n",
elsiocb->iotag, elsiocb->iocb.ulpContext,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- ndlp->nlp_rpi);
+ ndlp->nlp_rpi, vport->fc_flag);
if (ndlp->nlp_flag & NLP_LOGO_ACC) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
@@ -4936,8 +4968,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
- did = Fabric_DID;
-
if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
@@ -4976,26 +5006,82 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
+
+ /* If we have the high WWPN we can assign our own
+ * myDID; otherwise, we have to WAIT for a PLOGI
+ * from the remote NPort to find out what it
+ * will be.
+ */
+ vport->fc_myDID = PT2PT_LocalID;
}
+
+ /*
+ * The vport state should go to LPFC_FLOGI only
+ * AFTER we issue a FLOGI, not receive one.
+ */
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PT2PT;
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(shost->host_lock);
+
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI ACC rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
+
} else {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
+
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI LS_RJT rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
+
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
+
+ /* Now lets put fc_myDID back to what its supposed to be */
+ vport->fc_myDID = did;
+
return 1;
}
/* Send back ACC */
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+ /* Now lets put fc_myDID back to what its supposed to be */
+ vport->fc_myDID = did;
+
+ if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto fail;
+ }
+ }
+
return 0;
+fail:
+ return 1;
}
/**
@@ -5176,7 +5262,6 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t);
- mempool_free(pmb, phba->mbox_mem_pool);
elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
lpfc_max_els_tries, ndlp,
ndlp->nlp_DID, ELS_CMD_ACC);
@@ -5184,8 +5269,10 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Decrement the ndlp reference count from previous mbox command */
lpfc_nlp_put(ndlp);
- if (!elsiocb)
+ if (!elsiocb) {
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
+ }
icmd = &elsiocb->iocb;
icmd->ulpContext = rxid;
@@ -5202,7 +5289,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
-
+ mempool_free(pmb, phba->mbox_mem_pool);
/* Xmit ELS RLS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
"2874 Xmit ELS RLS ACC response tag x%x xri x%x, "
@@ -5586,7 +5673,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
pcmd += sizeof(uint32_t);
els_rrq = (struct RRQ *) pcmd;
- bf_set(rrq_oxid, els_rrq, rrq->xritag);
+ bf_set(rrq_oxid, els_rrq, phba->sli4_hba.xri_ids[rrq->xritag]);
bf_set(rrq_rxid, els_rrq, rrq->rxid);
bf_set(rrq_did, els_rrq, vport->fc_myDID);
els_rrq->rrq = cpu_to_be32(els_rrq->rrq);
@@ -7873,7 +7960,9 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
- lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
+ lpfc_set_rrq_active(phba, ndlp,
+ sglq_entry->sli4_lxritag,
+ rxid, 1);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index b507536dc5b..5bb269e224f 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -713,6 +713,7 @@ lpfc_do_work(void *p)
int rc;
set_user_nice(current, -20);
+ current->flags |= PF_NOFREEZE;
phba->data_flags = 0;
while (!kthread_should_stop()) {
@@ -1094,7 +1095,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI)
+ if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
lpfc_initial_flogi(vport);
return;
@@ -2881,9 +2882,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
}
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
- /* For private loop just start discovery and we are done. */
- if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
- !(vport->fc_flag & FC_PUBLIC_LOOP)) {
+ /*
+ * For private loop or for NPort pt2pt,
+ * just start discovery and we are done.
+ */
+ if ((vport->fc_flag & FC_PT2PT) ||
+ ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP))) {
+
/* Use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
/* Start discovery */
@@ -5490,9 +5496,9 @@ lpfc_nlp_release(struct kref *kref)
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
- "0279 lpfc_nlp_release: ndlp:x%p "
+ "0279 lpfc_nlp_release: ndlp:x%p did %x "
"usgmap:x%x refcnt:%d\n",
- (void *)ndlp, ndlp->nlp_usg_map,
+ (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map,
atomic_read(&ndlp->kref.refcount));
/* remove ndlp from action. */
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 5f280b5ae3d..41bb1d2fb62 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -3374,6 +3374,9 @@ typedef struct {
WORD5 w5; /* Header control/status word */
} XMT_SEQ_FIELDS64;
+/* This word is remote ports D_ID for XMIT_ELS_RSP64 */
+#define xmit_els_remoteID xrsqRo
+
/* IOCB Command template for 64 bit RCV_SEQUENCE64 */
typedef struct {
struct ulp_bde64 rcvBde;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 91f09761bd3..f1946dfda5b 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -228,19 +228,15 @@ struct lpfc_sli4_flags {
#define lpfc_idx_rsrc_rdy_MASK 0x00000001
#define lpfc_idx_rsrc_rdy_WORD word0
#define LPFC_IDX_RSRC_RDY 1
-#define lpfc_xri_rsrc_rdy_SHIFT 1
-#define lpfc_xri_rsrc_rdy_MASK 0x00000001
-#define lpfc_xri_rsrc_rdy_WORD word0
-#define LPFC_XRI_RSRC_RDY 1
-#define lpfc_rpi_rsrc_rdy_SHIFT 2
+#define lpfc_rpi_rsrc_rdy_SHIFT 1
#define lpfc_rpi_rsrc_rdy_MASK 0x00000001
#define lpfc_rpi_rsrc_rdy_WORD word0
#define LPFC_RPI_RSRC_RDY 1
-#define lpfc_vpi_rsrc_rdy_SHIFT 3
+#define lpfc_vpi_rsrc_rdy_SHIFT 2
#define lpfc_vpi_rsrc_rdy_MASK 0x00000001
#define lpfc_vpi_rsrc_rdy_WORD word0
#define LPFC_VPI_RSRC_RDY 1
-#define lpfc_vfi_rsrc_rdy_SHIFT 4
+#define lpfc_vfi_rsrc_rdy_SHIFT 3
#define lpfc_vfi_rsrc_rdy_MASK 0x00000001
#define lpfc_vfi_rsrc_rdy_WORD word0
#define LPFC_VFI_RSRC_RDY 1
@@ -3299,7 +3295,13 @@ struct els_request64_wqe {
struct xmit_els_rsp64_wqe {
struct ulp_bde64 bde;
uint32_t response_payload_len;
- uint32_t rsvd4;
+ uint32_t word4;
+#define els_rsp64_sid_SHIFT 0
+#define els_rsp64_sid_MASK 0x00FFFFFF
+#define els_rsp64_sid_WORD word4
+#define els_rsp64_sp_SHIFT 24
+#define els_rsp64_sp_MASK 0x00000001
+#define els_rsp64_sp_WORD word4
struct wqe_did wqe_dest;
struct wqe_common wqe_com; /* words 6-11 */
uint32_t word12;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 9598fdcb08a..411ed48d79d 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *);
static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);
static int lpfc_setup_endian_order(struct lpfc_hba *);
static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *);
-static void lpfc_free_sgl_list(struct lpfc_hba *);
-static int lpfc_init_sgl_list(struct lpfc_hba *);
+static void lpfc_free_els_sgl_list(struct lpfc_hba *);
+static void lpfc_init_sgl_list(struct lpfc_hba *);
static int lpfc_init_active_sgl_array(struct lpfc_hba *);
static void lpfc_free_active_sgl(struct lpfc_hba *);
static int lpfc_hba_down_post_s3(struct lpfc_hba *phba);
@@ -2767,47 +2767,14 @@ lpfc_offline(struct lpfc_hba *phba)
}
/**
- * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated.
- * @phba: pointer to lpfc hba data structure.
- *
- * This routine goes through all the scsi buffers in the system and updates the
- * Physical XRIs assigned to the SCSI buffer because these may change after any
- * firmware reset
- *
- * Return codes
- * 0 - successful (for now, it always returns 0)
- **/
-int
-lpfc_scsi_buf_update(struct lpfc_hba *phba)
-{
- struct lpfc_scsi_buf *sb, *sb_next;
-
- spin_lock_irq(&phba->hbalock);
- spin_lock(&phba->scsi_buf_list_lock);
- list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
- sb->cur_iocbq.sli4_xritag =
- phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag];
- set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask);
- phba->sli4_hba.max_cfg_param.xri_used++;
- phba->sli4_hba.xri_count++;
- }
- spin_unlock(&phba->scsi_buf_list_lock);
- spin_unlock_irq(&phba->hbalock);
- return 0;
-}
-
-/**
* lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists
* @phba: pointer to lpfc hba data structure.
*
* This routine is to free all the SCSI buffers and IOCBs from the driver
* list back to kernel. It is called from lpfc_pci_remove_one to free
* the internal resources before the device is removed from the system.
- *
- * Return codes
- * 0 - successful (for now, it always returns 0)
**/
-static int
+static void
lpfc_scsi_free(struct lpfc_hba *phba)
{
struct lpfc_scsi_buf *sb, *sb_next;
@@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba)
}
spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine first calculates the sizes of the current els and allocated
+ * scsi sgl lists, and then goes through all sgls to updates the physical
+ * XRIs assigned due to port function reset. During port initialization, the
+ * current els and allocated scsi sgl lists are 0s.
+ *
+ * Return codes
+ * 0 - successful (for now, it always returns 0)
+ **/
+int
+lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
+{
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL;
+ struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL;
+ uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt;
+ LIST_HEAD(els_sgl_list);
+ LIST_HEAD(scsi_sgl_list);
+ int rc;
+
+ /*
+ * update on pci function's els xri-sgl list
+ */
+ els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+ if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) {
+ /* els xri-sgl expanded */
+ xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt;
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3157 ELS xri-sgl count increased from "
+ "%d to %d\n", phba->sli4_hba.els_xri_cnt,
+ els_xri_cnt);
+ /* allocate the additional els sgls */
+ for (i = 0; i < xri_cnt; i++) {
+ sglq_entry = kzalloc(sizeof(struct lpfc_sglq),
+ GFP_KERNEL);
+ if (sglq_entry == NULL) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2562 Failure to allocate an "
+ "ELS sgl entry:%d\n", i);
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->buff_type = GEN_BUFF_TYPE;
+ sglq_entry->virt = lpfc_mbuf_alloc(phba, 0,
+ &sglq_entry->phys);
+ if (sglq_entry->virt == NULL) {
+ kfree(sglq_entry);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2563 Failure to allocate an "
+ "ELS mbuf:%d\n", i);
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->sgl = sglq_entry->virt;
+ memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
+ sglq_entry->state = SGL_FREED;
+ list_add_tail(&sglq_entry->list, &els_sgl_list);
+ }
+ spin_lock(&phba->hbalock);
+ list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock(&phba->hbalock);
+ } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) {
+ /* els xri-sgl shrinked */
+ xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt;
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3158 ELS xri-sgl count decreased from "
+ "%d to %d\n", phba->sli4_hba.els_xri_cnt,
+ els_xri_cnt);
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list);
+ spin_unlock_irq(&phba->hbalock);
+ /* release extra els sgls from list */
+ for (i = 0; i < xri_cnt; i++) {
+ list_remove_head(&els_sgl_list,
+ sglq_entry, struct lpfc_sglq, list);
+ if (sglq_entry) {
+ lpfc_mbuf_free(phba, sglq_entry->virt,
+ sglq_entry->phys);
+ kfree(sglq_entry);
+ }
+ }
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock_irq(&phba->hbalock);
+ } else
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3163 ELS xri-sgl count unchanged: %d\n",
+ els_xri_cnt);
+ phba->sli4_hba.els_xri_cnt = els_xri_cnt;
+
+ /* update xris to els sgls on the list */
+ sglq_entry = NULL;
+ sglq_entry_next = NULL;
+ list_for_each_entry_safe(sglq_entry, sglq_entry_next,
+ &phba->sli4_hba.lpfc_sgl_list, list) {
+ lxri = lpfc_sli4_next_xritag(phba);
+ if (lxri == NO_XRI) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2400 Failed to allocate xri for "
+ "ELS sgl\n");
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->sli4_lxritag = lxri;
+ sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
+ }
+
+ /*
+ * update on pci function's allocated scsi xri-sgl list
+ */
+ phba->total_scsi_bufs = 0;
+
+ /* maximum number of xris available for scsi buffers */
+ phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri -
+ els_xri_cnt;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2401 Current allocated SCSI xri-sgl count:%d, "
+ "maximum SCSI xri count:%d\n",
+ phba->sli4_hba.scsi_xri_cnt,
+ phba->sli4_hba.scsi_xri_max);
+
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
+
+ if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) {
+ /* max scsi xri shrinked below the allocated scsi buffers */
+ scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt -
+ phba->sli4_hba.scsi_xri_max;
+ /* release the extra allocated scsi buffers */
+ for (i = 0; i < scsi_xri_cnt; i++) {
+ list_remove_head(&scsi_sgl_list, psb,
+ struct lpfc_scsi_buf, list);
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data,
+ psb->dma_handle);
+ kfree(psb);
+ }
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt;
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
+ }
+
+ /* update xris associated to remaining allocated scsi buffers */
+ psb = NULL;
+ psb_next = NULL;
+ list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) {
+ lxri = lpfc_sli4_next_xritag(phba);
+ if (lxri == NO_XRI) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2560 Failed to allocate xri for "
+ "scsi buffer\n");
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ psb->cur_iocbq.sli4_lxritag = lxri;
+ psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
+ }
+ spin_lock(&phba->scsi_buf_list_lock);
+ list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list);
+ spin_unlock(&phba->scsi_buf_list_lock);
+
return 0;
+
+out_free_mem:
+ lpfc_free_els_sgl_list(phba);
+ lpfc_scsi_free(phba);
+ return rc;
}
/**
@@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (rc)
goto out_free_bsmbx;
- /* Initialize and populate the iocb list per host */
- rc = lpfc_init_sgl_list(phba);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1400 Failed to initialize sgl list.\n");
- goto out_destroy_cq_event_pool;
- }
+ /* Initialize sgl lists per host */
+ lpfc_init_sgl_list(phba);
+
+ /* Allocate and initialize active sgl array */
rc = lpfc_init_active_sgl_array(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1430 Failed to initialize sgl list.\n");
- goto out_free_sgl_list;
+ goto out_destroy_cq_event_pool;
}
rc = lpfc_sli4_init_rpi_hdrs(phba);
if (rc) {
@@ -4722,8 +4857,6 @@ out_remove_rpi_hdrs:
lpfc_sli4_remove_rpi_hdrs(phba);
out_free_active_sgl:
lpfc_free_active_sgl(phba);
-out_free_sgl_list:
- lpfc_free_sgl_list(phba);
out_destroy_cq_event_pool:
lpfc_sli4_cq_event_pool_destroy(phba);
out_free_bsmbx:
@@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
/* Free the ELS sgl list */
lpfc_free_active_sgl(phba);
- lpfc_free_sgl_list(phba);
-
- /* Free the SCSI sgl management array */
- kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+ lpfc_free_els_sgl_list(phba);
/* Free the completion queue EQ event pool */
lpfc_sli4_cq_event_release_all(phba);
@@ -4990,29 +5120,42 @@ out_free_iocbq:
}
/**
- * lpfc_free_sgl_list - Free sgl list.
+ * lpfc_free_sgl_list - Free a given sgl list.
* @phba: pointer to lpfc hba data structure.
+ * @sglq_list: pointer to the head of sgl list.
*
- * This routine is invoked to free the driver's sgl list and memory.
+ * This routine is invoked to free a give sgl list and memory.
**/
-static void
-lpfc_free_sgl_list(struct lpfc_hba *phba)
+void
+lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list)
{
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+
+ list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) {
+ list_del(&sglq_entry->list);
+ lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
+ kfree(sglq_entry);
+ }
+}
+
+/**
+ * lpfc_free_els_sgl_list - Free els sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's els sgl list and memory.
+ **/
+static void
+lpfc_free_els_sgl_list(struct lpfc_hba *phba)
+{
LIST_HEAD(sglq_list);
+ /* Retrieve all els sgls from driver list */
spin_lock_irq(&phba->hbalock);
list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list);
spin_unlock_irq(&phba->hbalock);
- list_for_each_entry_safe(sglq_entry, sglq_next,
- &sglq_list, list) {
- list_del(&sglq_entry->list);
- lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
- kfree(sglq_entry);
- phba->sli4_hba.total_sglq_bufs--;
- }
- kfree(phba->sli4_hba.lpfc_els_sgl_array);
+ /* Now free the sgl list */
+ lpfc_free_sgl_list(phba, &sglq_list);
}
/**
@@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba)
* This routine is invoked to allocate and initizlize the driver's sgl
* list and set up the sgl xritag tag array accordingly.
*
- * Return codes
- * 0 - successful
- * other values - error
**/
-static int
+static void
lpfc_init_sgl_list(struct lpfc_hba *phba)
{
- struct lpfc_sglq *sglq_entry = NULL;
- int i;
- int els_xri_cnt;
-
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2400 ELS XRI count %d.\n",
- els_xri_cnt);
/* Initialize and populate the sglq list per host/VF. */
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list);
- /* Sanity check on XRI management */
- if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2562 No room left for SCSI XRI allocation: "
- "max_xri=%d, els_xri=%d\n",
- phba->sli4_hba.max_cfg_param.max_xri,
- els_xri_cnt);
- return -ENOMEM;
- }
-
- /* Allocate memory for the ELS XRI management array */
- phba->sli4_hba.lpfc_els_sgl_array =
- kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt),
- GFP_KERNEL);
-
- if (!phba->sli4_hba.lpfc_els_sgl_array) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2401 Failed to allocate memory for ELS "
- "XRI management array of size %d.\n",
- els_xri_cnt);
- return -ENOMEM;
- }
+ /* els xri-sgl book keeping */
+ phba->sli4_hba.els_xri_cnt = 0;
- /* Keep the SCSI XRI into the XRI management array */
- phba->sli4_hba.scsi_xri_max =
- phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
+ /* scsi xri-buffer book keeping */
phba->sli4_hba.scsi_xri_cnt = 0;
- phba->sli4_hba.lpfc_scsi_psb_array =
- kzalloc((sizeof(struct lpfc_scsi_buf *) *
- phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
-
- if (!phba->sli4_hba.lpfc_scsi_psb_array) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2563 Failed to allocate memory for SCSI "
- "XRI management array of size %d.\n",
- phba->sli4_hba.scsi_xri_max);
- kfree(phba->sli4_hba.lpfc_els_sgl_array);
- return -ENOMEM;
- }
-
- for (i = 0; i < els_xri_cnt; i++) {
- sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL);
- if (sglq_entry == NULL) {
- printk(KERN_ERR "%s: only allocated %d sgls of "
- "expected %d count. Unloading driver.\n",
- __func__, i, els_xri_cnt);
- goto out_free_mem;
- }
-
- sglq_entry->buff_type = GEN_BUFF_TYPE;
- sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
- if (sglq_entry->virt == NULL) {
- kfree(sglq_entry);
- printk(KERN_ERR "%s: failed to allocate mbuf.\n"
- "Unloading driver.\n", __func__);
- goto out_free_mem;
- }
- sglq_entry->sgl = sglq_entry->virt;
- memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
-
- /* The list order is used by later block SGL registraton */
- spin_lock_irq(&phba->hbalock);
- sglq_entry->state = SGL_FREED;
- list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list);
- phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry;
- phba->sli4_hba.total_sglq_bufs++;
- spin_unlock_irq(&phba->hbalock);
- }
- return 0;
-
-out_free_mem:
- kfree(phba->sli4_hba.lpfc_scsi_psb_array);
- lpfc_free_sgl_list(phba);
- return -ENOMEM;
}
/**
@@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
phba->sli4_hba.u.if_type2.ERR2regaddr);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2890 Port error detected during port "
- "reset(%d): port status reg 0x%x, "
+ "reset(%d): wait_tmo:%d ms, "
+ "port status reg 0x%x, "
"error 1=0x%x, error 2=0x%x\n",
- num_resets, reg_data.word0,
+ num_resets, rdy_chk*10,
+ reg_data.word0,
phba->work_status[0],
phba->work_status[1]);
rc = -ENODEV;
@@ -8694,8 +8759,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
/* Release all the vports against this physical port */
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ continue;
fc_vport_terminate(vports[i]->fc_vport);
+ }
lpfc_destroy_vport_work_array(phba, vports);
/* Remove FC host and then SCSI host with the physical port */
@@ -9115,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
return 50;
else if (max_xri <= 1024)
return 100;
- else
+ else if (max_xri <= 1536)
return 150;
+ else if (max_xri <= 2048)
+ return 200;
+ else
+ return 250;
} else
return 0;
}
@@ -9455,8 +9527,11 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
/* Release all the vports against this physical port */
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ continue;
fc_vport_terminate(vports[i]->fc_vport);
+ }
lpfc_destroy_vport_work_array(phba, vports);
/* Remove FC host and then SCSI host with the physical port */
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 15ca2a9a0cd..9133a97f045 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -367,8 +367,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 1;
}
+ /* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) {
+
/* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -382,6 +384,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
+ /*
+ * For SLI4, the VFI/VPI are registered AFTER the
+ * Nport with the higher WWPN sends us a PLOGI with
+ * our assigned NPortId.
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_issue_reg_vfi(vport);
lpfc_can_disctmo(vport);
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 88f3a83dbd2..66e09069f28 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -399,6 +399,14 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
num_rsrc_err = atomic_read(&phba->num_rsrc_err);
num_cmd_success = atomic_read(&phba->num_cmd_success);
+ /*
+ * The error and success command counters are global per
+ * driver instance. If another handler has already
+ * operated on this error event, just exit.
+ */
+ if (num_rsrc_err == 0)
+ return;
+
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
@@ -688,7 +696,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (ndlp) {
- lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
+ lpfc_set_rrq_active(phba, ndlp,
+ psb->cur_iocbq.sli4_lxritag, rxid, 1);
lpfc_sli4_abts_err_handler(phba, ndlp, axri);
}
lpfc_release_scsi_buf_s4(phba, psb);
@@ -718,72 +727,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block
+ * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list
* @phba: pointer to lpfc hba data structure.
+ * @post_sblist: pointer to the scsi buffer list.
*
- * This routine walks the list of scsi buffers that have been allocated and
- * repost them to the HBA by using SGL block post. This is needed after a
- * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
- * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
- * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ * This routine walks a list of scsi buffers that was passed in. It attempts
+ * to construct blocks of scsi buffer sgls which contains contiguous xris and
+ * uses the non-embedded SGL block post mailbox commands to post to the port.
+ * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use
+ * embedded SGL post mailbox command for posting. The @post_sblist passed in
+ * must be local list, thus no lock is needed when manipulate the list.
*
- * Returns: 0 = success, non-zero failure.
+ * Returns: 0 = failure, non-zero number of successfully posted buffers.
**/
int
-lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba,
+ struct list_head *post_sblist, int sb_count)
{
- struct lpfc_scsi_buf *psb;
- int index, status, bcnt = 0, rcnt = 0, rc = 0;
- LIST_HEAD(sblist);
-
- for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) {
- psb = phba->sli4_hba.lpfc_scsi_psb_array[index];
- if (psb) {
- /* Remove from SCSI buffer list */
- list_del(&psb->list);
- /* Add it to a local SCSI buffer list */
- list_add_tail(&psb->list, &sblist);
- if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) {
- bcnt = rcnt;
- rcnt = 0;
+ struct lpfc_scsi_buf *psb, *psb_next;
+ int status;
+ int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0;
+ dma_addr_t pdma_phys_bpl1;
+ int last_xritag = NO_XRI;
+ LIST_HEAD(prep_sblist);
+ LIST_HEAD(blck_sblist);
+ LIST_HEAD(scsi_sblist);
+
+ /* sanity check */
+ if (sb_count <= 0)
+ return -EINVAL;
+
+ list_for_each_entry_safe(psb, psb_next, post_sblist, list) {
+ list_del_init(&psb->list);
+ block_cnt++;
+ if ((last_xritag != NO_XRI) &&
+ (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) {
+ /* a hole in xri block, form a sgl posting block */
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt - 1;
+ /* prepare list for next posting block */
+ list_add_tail(&psb->list, &prep_sblist);
+ block_cnt = 1;
+ } else {
+ /* prepare list for next posting block */
+ list_add_tail(&psb->list, &prep_sblist);
+ /* enough sgls for non-embed sgl mbox command */
+ if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt;
+ block_cnt = 0;
}
- } else
- /* A hole present in the XRI array, need to skip */
- bcnt = rcnt;
+ }
+ num_posting++;
+ last_xritag = psb->cur_iocbq.sli4_xritag;
- if (index == phba->sli4_hba.scsi_xri_cnt - 1)
- /* End of XRI array for SCSI buffer, complete */
- bcnt = rcnt;
+ /* end of repost sgl list condition for SCSI buffers */
+ if (num_posting == sb_count) {
+ if (post_cnt == 0) {
+ /* last sgl posting block */
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt;
+ } else if (block_cnt == 1) {
+ /* last single sgl with non-contiguous xri */
+ if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+ pdma_phys_bpl1 = psb->dma_phys_bpl +
+ SGL_PAGE_SIZE;
+ else
+ pdma_phys_bpl1 = 0;
+ status = lpfc_sli4_post_sgl(phba,
+ psb->dma_phys_bpl,
+ pdma_phys_bpl1,
+ psb->cur_iocbq.sli4_xritag);
+ if (status) {
+ /* failure, put on abort scsi list */
+ psb->exch_busy = 1;
+ } else {
+ /* success, put on SCSI buffer list */
+ psb->exch_busy = 0;
+ psb->status = IOSTAT_SUCCESS;
+ num_posted++;
+ }
+ /* success, put on SCSI buffer sgl list */
+ list_add_tail(&psb->list, &scsi_sblist);
+ }
+ }
- /* Continue until collect up to a nembed page worth of sgls */
- if (bcnt == 0)
+ /* continue until a nembed page worth of sgls */
+ if (post_cnt == 0)
continue;
- /* Now, post the SCSI buffer list sgls as a block */
- if (!phba->sli4_hba.extents_in_use)
- status = lpfc_sli4_post_scsi_sgl_block(phba,
- &sblist,
- bcnt);
- else
- status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
- &sblist,
- bcnt);
- /* Reset SCSI buffer count for next round of posting */
- bcnt = 0;
- while (!list_empty(&sblist)) {
- list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
- list);
+
+ /* post block of SCSI buffer list sgls */
+ status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist,
+ post_cnt);
+
+ /* don't reset xirtag due to hole in xri block */
+ if (block_cnt == 0)
+ last_xritag = NO_XRI;
+
+ /* reset SCSI buffer post count for next round of posting */
+ post_cnt = 0;
+
+ /* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */
+ while (!list_empty(&blck_sblist)) {
+ list_remove_head(&blck_sblist, psb,
+ struct lpfc_scsi_buf, list);
if (status) {
- /* Put this back on the abort scsi list */
+ /* failure, put on abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
+ /* success, put on SCSI buffer list */
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
+ num_posted++;
}
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
+ list_add_tail(&psb->list, &scsi_sblist);
}
}
+ /* Push SCSI buffers with sgl posted to the availble list */
+ while (!list_empty(&scsi_sblist)) {
+ list_remove_head(&scsi_sblist, psb,
+ struct lpfc_scsi_buf, list);
+ lpfc_release_scsi_buf_s4(phba, psb);
+ }
+ return num_posted;
+}
+
+/**
+ * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of scsi buffers that have been allocated and
+ * repost them to the port by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
+ * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
+ * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+int
+lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+{
+ LIST_HEAD(post_sblist);
+ int num_posted, rc = 0;
+
+ /* get all SCSI buffers need to repost to a local list */
+ spin_lock(&phba->scsi_buf_list_lock);
+ list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist);
+ spin_unlock(&phba->scsi_buf_list_lock);
+
+ /* post the list of scsi buffer sgls to port if available */
+ if (!list_empty(&post_sblist)) {
+ num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist,
+ phba->sli4_hba.scsi_xri_cnt);
+ /* failed to post any scsi buffer, return error */
+ if (num_posted == 0)
+ rc = -EIO;
+ }
return rc;
}
@@ -792,12 +891,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
* @vport: The virtual port for which this call being executed.
* @num_to_allocate: The requested number of buffers to allocate.
*
- * This routine allocates a scsi buffer for device with SLI-4 interface spec,
+ * This routine allocates scsi buffers for device with SLI-4 interface spec,
* the scsi buffer contains all the necessary information needed to initiate
- * a SCSI I/O.
+ * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put
+ * them on a list, it post them to the port by using SGL block post.
*
* Return codes:
- * int - number of scsi buffers that were allocated.
+ * int - number of scsi buffers that were allocated and posted.
* 0 = failure, less than num_to_alloc is a partial failure.
**/
static int
@@ -810,22 +910,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
dma_addr_t pdma_phys_fcp_cmd;
dma_addr_t pdma_phys_fcp_rsp;
dma_addr_t pdma_phys_bpl, pdma_phys_bpl1;
- uint16_t iotag, last_xritag = NO_XRI, lxri = 0;
- int status = 0, index;
- int bcnt;
- int non_sequential_xri = 0;
- LIST_HEAD(sblist);
+ uint16_t iotag, lxri = 0;
+ int bcnt, num_posted;
+ LIST_HEAD(prep_sblist);
+ LIST_HEAD(post_sblist);
+ LIST_HEAD(scsi_sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
if (!psb)
break;
-
/*
- * Get memory from the pci pool to map the virt space to pci bus
- * space for an I/O. The DMA buffer includes space for the
- * struct fcp_cmnd, struct fcp_rsp and the number of bde's
- * necessary to support the sg_tablesize.
+ * Get memory from the pci pool to map the virt space to
+ * pci bus space for an I/O. The DMA buffer includes space
+ * for the struct fcp_cmnd, struct fcp_rsp and the number
+ * of bde's necessary to support the sg_tablesize.
*/
psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
GFP_KERNEL, &psb->dma_handle);
@@ -833,8 +932,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
kfree(psb);
break;
}
-
- /* Initialize virtual ptrs to dma_buf region. */
memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
/* Allocate iotag for psb->cur_iocbq. */
@@ -855,16 +952,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
psb->cur_iocbq.sli4_lxritag = lxri;
psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
- if (last_xritag != NO_XRI
- && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) {
- non_sequential_xri = 1;
- } else
- list_add_tail(&psb->list, &sblist);
- last_xritag = psb->cur_iocbq.sli4_xritag;
-
- index = phba->sli4_hba.scsi_xri_cnt++;
psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
-
psb->fcp_bpl = psb->data;
psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size)
- (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
@@ -880,9 +968,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
/*
- * The first two bdes are the FCP_CMD and FCP_RSP. The balance
- * are sg list bdes. Initialize the first two and leave the
- * rest for queuecommand.
+ * The first two bdes are the FCP_CMD and FCP_RSP.
+ * The balance are sg list bdes. Initialize the
+ * first two and leave the rest for queuecommand.
*/
sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
@@ -917,62 +1005,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
iocb->ulpBdeCount = 1;
iocb->ulpLe = 1;
iocb->ulpClass = CLASS3;
- psb->cur_iocbq.context1 = psb;
+ psb->cur_iocbq.context1 = psb;
if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE;
else
pdma_phys_bpl1 = 0;
psb->dma_phys_bpl = pdma_phys_bpl;
- phba->sli4_hba.lpfc_scsi_psb_array[index] = psb;
- if (non_sequential_xri) {
- status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl,
- pdma_phys_bpl1,
- psb->cur_iocbq.sli4_xritag);
- if (status) {
- /* Put this back on the abort scsi list */
- psb->exch_busy = 1;
- } else {
- psb->exch_busy = 0;
- psb->status = IOSTAT_SUCCESS;
- }
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
- break;
- }
- }
- if (bcnt) {
- if (!phba->sli4_hba.extents_in_use)
- status = lpfc_sli4_post_scsi_sgl_block(phba,
- &sblist,
- bcnt);
- else
- status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
- &sblist,
- bcnt);
-
- if (status) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "3021 SCSI SGL post error %d\n",
- status);
- bcnt = 0;
- }
- /* Reset SCSI buffer count for next round of posting */
- while (!list_empty(&sblist)) {
- list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
- list);
- if (status) {
- /* Put this back on the abort scsi list */
- psb->exch_busy = 1;
- } else {
- psb->exch_busy = 0;
- psb->status = IOSTAT_SUCCESS;
- }
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
- }
+
+ /* add the scsi buffer to a post list */
+ list_add_tail(&psb->list, &post_sblist);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ phba->sli4_hba.scsi_xri_cnt++;
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
}
+ lpfc_printf_log(phba, KERN_INFO, LOG_BG,
+ "3021 Allocate %d out of %d requested new SCSI "
+ "buffers\n", bcnt, num_to_alloc);
+
+ /* post the list of scsi buffer sgls to port if available */
+ if (!list_empty(&post_sblist))
+ num_posted = lpfc_sli4_post_scsi_sgl_list(phba,
+ &post_sblist, bcnt);
+ else
+ num_posted = 0;
- return bcnt + non_sequential_xri;
+ return num_posted;
}
/**
@@ -1043,7 +1100,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list,
list) {
if (lpfc_test_rrq_active(phba, ndlp,
- lpfc_cmd->cur_iocbq.sli4_xritag))
+ lpfc_cmd->cur_iocbq.sli4_lxritag))
continue;
list_del(&lpfc_cmd->list);
found = 1;
@@ -1897,7 +1954,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
dma_addr_t physaddr;
int i = 0, num_bde = 0, status;
int datadir = sc->sc_data_direction;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t reftag;
unsigned blksize;
@@ -2034,7 +2093,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
int datadir = sc->sc_data_direction;
unsigned char pgdone = 0, alldone = 0;
unsigned blksize;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t reftag;
uint8_t txop, rxop;
@@ -2253,7 +2314,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t reftag;
unsigned blksize;
uint8_t txop, rxop;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t dma_len;
uint32_t dma_offset = 0;
@@ -2383,7 +2446,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t reftag;
uint8_t txop, rxop;
uint32_t dma_len;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t dma_offset = 0;
int num_sge = 0;
@@ -3604,11 +3669,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
logit = LOG_FCP | LOG_FCP_UNDER;
lpfc_printf_vlog(vport, KERN_WARNING, logit,
"9030 FCP cmd x%x failed <%d/%d> "
- "status: x%x result: x%x Data: x%x x%x\n",
+ "status: x%x result: x%x "
+ "sid: x%x did: x%x oxid: x%x "
+ "Data: x%x x%x\n",
cmd->cmnd[0],
cmd->device ? cmd->device->id : 0xffff,
cmd->device ? cmd->device->lun : 0xffff,
lpfc_cmd->status, lpfc_cmd->result,
+ vport->fc_myDID, pnode->nlp_DID,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
pIocbOut->iocb.ulpContext,
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
@@ -3689,8 +3759,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
* ABTS we cannot generate and RRQ.
*/
lpfc_set_rrq_active(phba, pnode,
- lpfc_cmd->cur_iocbq.sli4_xritag,
- 0, 0);
+ lpfc_cmd->cur_iocbq.sli4_lxritag,
+ 0, 0);
}
/* else: fall through */
default:
@@ -4348,8 +4418,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
ret = fc_block_scsi_eh(cmnd);
if (ret)
return ret;
+
+ spin_lock_irq(&phba->hbalock);
+ /* driver queued commands are in process of being flushed */
+ if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3168 SCSI Layer abort requested I/O has been "
+ "flushed by LLD.\n");
+ return FAILED;
+ }
+
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
if (!lpfc_cmd) {
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"2873 SCSI Layer I/O Abort Request IO CMPL Status "
"x%x ID %d LUN %d\n",
@@ -4357,23 +4439,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
return SUCCESS;
}
+ iocb = &lpfc_cmd->cur_iocbq;
+ /* the command is in process of being cancelled */
+ if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3169 SCSI Layer abort requested I/O has been "
+ "cancelled by LLD.\n");
+ return FAILED;
+ }
/*
* If pCmd field of the corresponding lpfc_scsi_buf structure
* points to a different SCSI command, then the driver has
* already completed this command, but the midlayer did not
- * see the completion before the eh fired. Just return
- * SUCCESS.
+ * see the completion before the eh fired. Just return SUCCESS.
*/
- iocb = &lpfc_cmd->cur_iocbq;
- if (lpfc_cmd->pCmd != cmnd)
- goto out;
+ if (lpfc_cmd->pCmd != cmnd) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3170 SCSI Layer abort requested I/O has been "
+ "completed by LLD.\n");
+ goto out_unlock;
+ }
BUG_ON(iocb->context1 != lpfc_cmd);
- abtsiocb = lpfc_sli_get_iocbq(phba);
+ abtsiocb = __lpfc_sli_get_iocbq(phba);
if (abtsiocb == NULL) {
ret = FAILED;
- goto out;
+ goto out_unlock;
}
/*
@@ -4405,6 +4498,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
abtsiocb->vport = vport;
+ /* no longer need the lock after this point */
+ spin_unlock_irq(&phba->hbalock);
+
if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==
IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, abtsiocb);
@@ -4421,10 +4517,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
wait_event_timeout(waitq,
(lpfc_cmd->pCmd != cmnd),
(2*vport->cfg_devloss_tmo*HZ));
-
- spin_lock_irq(shost->host_lock);
lpfc_cmd->waitq = NULL;
- spin_unlock_irq(shost->host_lock);
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
@@ -4434,8 +4527,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
"LUN %d\n",
ret, cmnd->device->id, cmnd->device->lun);
}
+ goto out;
- out:
+out_unlock:
+ spin_unlock_irq(&phba->hbalock);
+out:
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"0749 SCSI Layer I/O Abort Request Status x%x ID %d "
"LUN %d\n", ret, cmnd->device->id,
@@ -4863,6 +4959,43 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
}
/**
+ * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt
+ * @cmnd: Pointer to scsi_cmnd data structure.
+ *
+ * This routine does host reset to the adaptor port. It brings the HBA
+ * offline, performs a board restart, and then brings the board back online.
+ * The lpfc_offline calls lpfc_sli_hba_down which will abort and local
+ * reject all outstanding SCSI commands to the host and error returned
+ * back to SCSI mid-level. As this will be SCSI mid-level's last resort
+ * of error handling, it will only return error if resetting of the adapter
+ * is not successful; in all other cases, will return success.
+ *
+ * Return code :
+ * 0x2003 - Error
+ * 0x2002 - Success
+ **/
+static int
+lpfc_host_reset_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int rc, ret = SUCCESS;
+
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ rc = lpfc_sli_brdrestart(phba);
+ if (rc)
+ ret = FAILED;
+ lpfc_online(phba);
+ lpfc_unblock_mgmt_io(phba);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "3172 SCSI layer issued Host Reset Data: x%x\n", ret);
+ return ret;
+}
+
+/**
* lpfc_slave_alloc - scsi_host_template slave_alloc entry point
* @sdev: Pointer to scsi_device.
*
@@ -4994,6 +5127,7 @@ struct scsi_host_template lpfc_template = {
.eh_device_reset_handler = lpfc_device_reset_handler,
.eh_target_reset_handler = lpfc_target_reset_handler,
.eh_bus_reset_handler = lpfc_bus_reset_handler,
+ .eh_host_reset_handler = lpfc_host_reset_handler,
.slave_alloc = lpfc_slave_alloc,
.slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index dbaf5b963bf..b4720a10981 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -67,6 +67,8 @@ static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
struct hbq_dmabuf *);
static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *,
struct lpfc_cqe *);
+static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *,
+ int);
static IOCB_t *
lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
@@ -500,7 +502,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* allocation is successful, it returns pointer to the newly
* allocated iocb object else it returns NULL.
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
@@ -875,6 +877,9 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
} else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) &&
!(piocbq->iocb_flag & LPFC_IO_LIBDFC))
ndlp = piocbq->context_un.ndlp;
+ else if ((piocbq->iocb.ulpCommand == CMD_ELS_REQUEST64_CR) &&
+ (piocbq->iocb_flag & LPFC_IO_LIBDFC))
+ ndlp = piocbq->context_un.ndlp;
else
ndlp = piocbq->context1;
@@ -883,7 +888,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
while (!found) {
if (!sglq)
return NULL;
- if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
+ if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_lxritag)) {
/* This xri has an rrq outstanding for this DID.
* put it back in the list and get another xri.
*/
@@ -1257,7 +1262,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
- piocb->iocb_flag |= LPFC_IO_ON_Q;
+ piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt++;
if (pring->txcmplq_cnt > pring->txcmplq_max)
pring->txcmplq_max = pring->txcmplq_cnt;
@@ -2556,9 +2561,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
pring->txcmplq_cnt--;
- cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
}
return cmd_iocb;
}
@@ -2591,14 +2596,14 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
- list_del_init(&cmd_iocb->list);
- if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
- cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
+ /* remove from txcmpl queue list */
+ list_del_init(&cmd_iocb->list);
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt--;
+ return cmd_iocb;
}
- return cmd_iocb;
}
-
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0372 iotag x%x is out off range: max iotag (x%x)\n",
iotag, phba->sli.last_iotag);
@@ -3466,6 +3471,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
pring->txcmplq_cnt = 0;
+
+ /* Indicate the I/O queues are flushed */
+ phba->hba_flag |= HBA_FCP_IOQ_FLUSH;
spin_unlock_irq(&phba->hbalock);
/* Flush the txq */
@@ -3877,6 +3885,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
uint16_t cfg_value;
+ int rc;
/* Reset HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3905,12 +3914,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
/* Perform FCoE PCI function reset */
lpfc_sli4_queue_destroy(phba);
- lpfc_pci_function_reset(phba);
+ rc = lpfc_pci_function_reset(phba);
/* Restore PCI cmd register */
pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
- return 0;
+ return rc;
}
/**
@@ -4002,6 +4011,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
uint32_t hba_aer_enabled;
+ int rc;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -4011,7 +4021,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
/* Take PCIe device Advanced Error Reporting (AER) state */
hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
- lpfc_sli4_brdreset(phba);
+ rc = lpfc_sli4_brdreset(phba);
spin_lock_irq(&phba->hbalock);
phba->pport->stopped = 0;
@@ -4028,7 +4038,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
lpfc_hba_down_post(phba);
- return 0;
+ return rc;
}
/**
@@ -4967,7 +4977,12 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
&rsrc_info->u.rsp);
*extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size,
&rsrc_info->u.rsp);
- err_exit:
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3162 Retrieved extents type-%d from port: count:%d, "
+ "size:%d\n", type, *extnt_count, *extnt_size);
+
+err_exit:
mempool_free(mbox, phba->mbox_mem_pool);
return rc;
}
@@ -5051,7 +5066,7 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type)
* 0: if successful
**/
static int
-lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
+lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt,
uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox)
{
int rc = 0;
@@ -5060,7 +5075,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
uint32_t alloc_len, mbox_tmo;
/* Calculate the total requested length of the dma memory */
- req_len = *extnt_cnt * sizeof(uint16_t);
+ req_len = extnt_cnt * sizeof(uint16_t);
/*
* Calculate the size of an embedded mailbox. The uint32_t
@@ -5075,7 +5090,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
*/
*emb = LPFC_SLI4_MBX_EMBED;
if (req_len > emb_len) {
- req_len = *extnt_cnt * sizeof(uint16_t) +
+ req_len = extnt_cnt * sizeof(uint16_t) +
sizeof(union lpfc_sli4_cfg_shdr) +
sizeof(uint32_t);
*emb = LPFC_SLI4_MBX_NEMBED;
@@ -5091,7 +5106,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
"size (x%x)\n", alloc_len, req_len);
return -ENOMEM;
}
- rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb);
+ rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb);
if (unlikely(rc))
return -EIO;
@@ -5149,17 +5164,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
return -ENOMEM;
}
- lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT,
- "2903 Available Resource Extents "
- "for resource type 0x%x: Count: 0x%x, "
- "Size 0x%x\n", type, rsrc_cnt,
- rsrc_size);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI,
+ "2903 Post resource extents type-0x%x: "
+ "count:%d, size %d\n", type, rsrc_cnt, rsrc_size);
mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return -ENOMEM;
- rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox);
+ rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox);
if (unlikely(rc)) {
rc = -EIO;
goto err_exit;
@@ -5250,6 +5263,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
rc = -ENOMEM;
goto err_exit;
}
+ phba->sli4_hba.max_cfg_param.xri_used = 0;
phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt *
sizeof(uint16_t),
GFP_KERNEL);
@@ -5420,7 +5434,6 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
case LPFC_RSC_TYPE_FCOE_XRI:
kfree(phba->sli4_hba.xri_bmask);
kfree(phba->sli4_hba.xri_ids);
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
&phba->sli4_hba.lpfc_xri_blk_list, list) {
list_del_init(&rsrc_blk->list);
@@ -5612,7 +5625,6 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba)
goto free_vpi_ids;
}
phba->sli4_hba.max_cfg_param.xri_used = 0;
- phba->sli4_hba.xri_count = 0;
phba->sli4_hba.xri_ids = kzalloc(count *
sizeof(uint16_t),
GFP_KERNEL);
@@ -5694,7 +5706,6 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
kfree(phba->sli4_hba.xri_bmask);
kfree(phba->sli4_hba.xri_ids);
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
kfree(phba->sli4_hba.vfi_bmask);
kfree(phba->sli4_hba.vfi_ids);
bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
@@ -5853,6 +5864,149 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
}
/**
+ * lpfc_sli4_repost_els_sgl_list - Repsot the els buffers sgl pages as block
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of els buffers that have been allocated and
+ * repost them to the port by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. It attempts to construct blocks
+ * of els buffer sgls which contains contiguous xris and uses the non-embedded
+ * SGL block post mailbox commands to post them to the port. For single els
+ * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post
+ * mailbox command for posting.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+static int
+lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
+{
+ struct lpfc_sglq *sglq_entry = NULL;
+ struct lpfc_sglq *sglq_entry_next = NULL;
+ struct lpfc_sglq *sglq_entry_first = NULL;
+ int status, post_cnt = 0, num_posted = 0, block_cnt = 0;
+ int last_xritag = NO_XRI;
+ LIST_HEAD(prep_sgl_list);
+ LIST_HEAD(blck_sgl_list);
+ LIST_HEAD(allc_sgl_list);
+ LIST_HEAD(post_sgl_list);
+ LIST_HEAD(free_sgl_list);
+
+ spin_lock(&phba->hbalock);
+ list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list);
+ spin_unlock(&phba->hbalock);
+
+ list_for_each_entry_safe(sglq_entry, sglq_entry_next,
+ &allc_sgl_list, list) {
+ list_del_init(&sglq_entry->list);
+ block_cnt++;
+ if ((last_xritag != NO_XRI) &&
+ (sglq_entry->sli4_xritag != last_xritag + 1)) {
+ /* a hole in xri block, form a sgl posting block */
+ list_splice_init(&prep_sgl_list, &blck_sgl_list);
+ post_cnt = block_cnt - 1;
+ /* prepare list for next posting block */
+ list_add_tail(&sglq_entry->list, &prep_sgl_list);
+ block_cnt = 1;
+ } else {
+ /* prepare list for next posting block */
+ list_add_tail(&sglq_entry->list, &prep_sgl_list);
+ /* enough sgls for non-embed sgl mbox command */
+ if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+ list_splice_init(&prep_sgl_list,
+ &blck_sgl_list);
+ post_cnt = block_cnt;
+ block_cnt = 0;
+ }
+ }
+ num_posted++;
+
+ /* keep track of last sgl's xritag */
+ last_xritag = sglq_entry->sli4_xritag;
+
+ /* end of repost sgl list condition for els buffers */
+ if (num_posted == phba->sli4_hba.els_xri_cnt) {
+ if (post_cnt == 0) {
+ list_splice_init(&prep_sgl_list,
+ &blck_sgl_list);
+ post_cnt = block_cnt;
+ } else if (block_cnt == 1) {
+ status = lpfc_sli4_post_sgl(phba,
+ sglq_entry->phys, 0,
+ sglq_entry->sli4_xritag);
+ if (!status) {
+ /* successful, put sgl to posted list */
+ list_add_tail(&sglq_entry->list,
+ &post_sgl_list);
+ } else {
+ /* Failure, put sgl to free list */
+ lpfc_printf_log(phba, KERN_WARNING,
+ LOG_SLI,
+ "3159 Failed to post els "
+ "sgl, xritag:x%x\n",
+ sglq_entry->sli4_xritag);
+ list_add_tail(&sglq_entry->list,
+ &free_sgl_list);
+ spin_lock_irq(&phba->hbalock);
+ phba->sli4_hba.els_xri_cnt--;
+ spin_unlock_irq(&phba->hbalock);
+ }
+ }
+ }
+
+ /* continue until a nembed page worth of sgls */
+ if (post_cnt == 0)
+ continue;
+
+ /* post the els buffer list sgls as a block */
+ status = lpfc_sli4_post_els_sgl_list(phba, &blck_sgl_list,
+ post_cnt);
+
+ if (!status) {
+ /* success, put sgl list to posted sgl list */
+ list_splice_init(&blck_sgl_list, &post_sgl_list);
+ } else {
+ /* Failure, put sgl list to free sgl list */
+ sglq_entry_first = list_first_entry(&blck_sgl_list,
+ struct lpfc_sglq,
+ list);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "3160 Failed to post els sgl-list, "
+ "xritag:x%x-x%x\n",
+ sglq_entry_first->sli4_xritag,
+ (sglq_entry_first->sli4_xritag +
+ post_cnt - 1));
+ list_splice_init(&blck_sgl_list, &free_sgl_list);
+ spin_lock_irq(&phba->hbalock);
+ phba->sli4_hba.els_xri_cnt -= post_cnt;
+ spin_unlock_irq(&phba->hbalock);
+ }
+
+ /* don't reset xirtag due to hole in xri block */
+ if (block_cnt == 0)
+ last_xritag = NO_XRI;
+
+ /* reset els sgl post count for next round of posting */
+ post_cnt = 0;
+ }
+
+ /* free the els sgls failed to post */
+ lpfc_free_sgl_list(phba, &free_sgl_list);
+
+ /* push els sgls posted to the availble list */
+ if (!list_empty(&post_sgl_list)) {
+ spin_lock(&phba->hbalock);
+ list_splice_init(&post_sgl_list,
+ &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "3161 Failure to post els sgl to port.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
* lpfc_sli4_hba_setup - SLI4 device intialization PCI function
* @phba: Pointer to HBA context object.
*
@@ -5923,6 +6077,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
else
phba->hba_flag &= ~HBA_FIP_SUPPORT;
+ phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH;
+
if (phba->sli_rev != LPFC_SLI_REV4) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"0376 READ_REV Error. SLI Level %d "
@@ -6063,8 +6219,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"rc = x%x\n", rc);
goto out_free_mbox;
}
- /* update physical xri mappings in the scsi buffers */
- lpfc_scsi_buf_update(phba);
/* Read the port's service parameters. */
rc = lpfc_read_sparam(phba, mboxq, vport->vpi);
@@ -6105,28 +6259,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
- /* Register SGL pool to the device using non-embedded mailbox command */
- if (!phba->sli4_hba.extents_in_use) {
- rc = lpfc_sli4_post_els_sgl_list(phba);
- if (unlikely(rc)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "0582 Error %d during els sgl post "
- "operation\n", rc);
- rc = -ENODEV;
- goto out_free_mbox;
- }
- } else {
- rc = lpfc_sli4_post_els_sgl_list_ext(phba);
- if (unlikely(rc)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "2560 Error %d during els sgl post "
- "operation\n", rc);
- rc = -ENODEV;
- goto out_free_mbox;
- }
+ /* update host els and scsi xri-sgl sizes and mappings */
+ rc = lpfc_sli4_xri_sgl_update(phba);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "1400 Failed to update xri-sgl size and "
+ "mapping: %d\n", rc);
+ goto out_free_mbox;
}
- /* Register SCSI SGL pool to the device */
+ /* register the els sgl pool to the port */
+ rc = lpfc_sli4_repost_els_sgl_list(phba);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "0582 Error %d during els sgl post "
+ "operation\n", rc);
+ rc = -ENODEV;
+ goto out_free_mbox;
+ }
+
+ /* register the allocated scsi sgl pool to the port */
rc = lpfc_sli4_repost_scsi_sgl_list(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
@@ -7060,14 +7212,19 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
if (rc != MBX_SUCCESS)
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
"(%d):2541 Mailbox command x%x "
- "(x%x/x%x) cannot issue Data: "
- "x%x x%x\n",
+ "(x%x/x%x) failure: "
+ "mqe_sta: x%x mcqe_sta: x%x/x%x "
+ "Data: x%x x%x\n,",
mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli_config_mbox_subsys_get(phba,
mboxq),
lpfc_sli_config_mbox_opcode_get(phba,
mboxq),
+ bf_get(lpfc_mqe_status, &mboxq->u.mqe),
+ bf_get(lpfc_mcqe_status, &mboxq->mcqe),
+ bf_get(lpfc_mcqe_ext_status,
+ &mboxq->mcqe),
psli->sli_flag, flag);
return rc;
} else if (flag == MBX_POLL) {
@@ -7086,18 +7243,22 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
/* Successfully blocked, now issue sync mbox cmd */
rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
if (rc != MBX_SUCCESS)
- lpfc_printf_log(phba, KERN_ERR,
+ lpfc_printf_log(phba, KERN_WARNING,
LOG_MBOX | LOG_SLI,
- "(%d):2597 Mailbox command "
- "x%x (x%x/x%x) cannot issue "
- "Data: x%x x%x\n",
- mboxq->vport ?
- mboxq->vport->vpi : 0,
+ "(%d):2597 Sync Mailbox command "
+ "x%x (x%x/x%x) failure: "
+ "mqe_sta: x%x mcqe_sta: x%x/x%x "
+ "Data: x%x x%x\n,",
+ mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli_config_mbox_subsys_get(phba,
mboxq),
lpfc_sli_config_mbox_opcode_get(phba,
mboxq),
+ bf_get(lpfc_mqe_status, &mboxq->u.mqe),
+ bf_get(lpfc_mcqe_status, &mboxq->mcqe),
+ bf_get(lpfc_mcqe_ext_status,
+ &mboxq->mcqe),
psli->sli_flag, flag);
/* Unblock the async mailbox posting afterward */
lpfc_sli4_async_mbox_unblock(phba);
@@ -7712,7 +7873,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
switch (iocbq->iocb.ulpCommand) {
case CMD_ELS_REQUEST64_CR:
- ndlp = (struct lpfc_nodelist *)iocbq->context1;
+ if (iocbq->iocb_flag & LPFC_IO_LIBDFC)
+ ndlp = iocbq->context_un.ndlp;
+ else
+ ndlp = (struct lpfc_nodelist *)iocbq->context1;
if (!iocbq->iocb.ulpLe) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2007 Only Limited Edition cmd Format"
@@ -7751,9 +7915,13 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(els_req64_sp, &wqe->els_req, 1);
bf_set(els_req64_sid, &wqe->els_req,
iocbq->vport->fc_myDID);
+ if ((*pcmd == ELS_CMD_FLOGI) &&
+ !(phba->fc_topology ==
+ LPFC_TOPOLOGY_LOOP))
+ bf_set(els_req64_sid, &wqe->els_req, 0);
bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
- phba->vpi_ids[phba->pport->vpi]);
+ phba->vpi_ids[iocbq->vport->vpi]);
} else if (pcmd && iocbq->context1) {
bf_set(wqe_ct, &wqe->els_req.wqe_com, 0);
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
@@ -7908,11 +8076,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
/* words0-2 BDE memcpy */
/* word3 iocb=iotag32 wqe=response_payload_len */
wqe->xmit_els_rsp.response_payload_len = xmit_len;
- /* word4 iocb=did wge=rsvd. */
- wqe->xmit_els_rsp.rsvd4 = 0;
+ /* word4 */
+ wqe->xmit_els_rsp.word4 = 0;
/* word5 iocb=rsvd wge=did */
bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
- iocbq->iocb.un.elsreq64.remoteID);
+ iocbq->iocb.un.xseq64.xmit_els_remoteID);
+
+ if_type = bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf);
+ if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (iocbq->vport->fc_flag & FC_PT2PT) {
+ bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
+ bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
+ iocbq->vport->fc_myDID);
+ if (iocbq->vport->fc_myDID == Fabric_DID) {
+ bf_set(wqe_els_did,
+ &wqe->xmit_els_rsp.wqe_dest, 0);
+ }
+ }
+ }
bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
@@ -7932,11 +8114,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
iocbq->context2)->virt);
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
- bf_set(els_req64_sp, &wqe->els_req, 1);
- bf_set(els_req64_sid, &wqe->els_req,
+ bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
+ bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
iocbq->vport->fc_myDID);
- bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
- bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
+ bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1);
+ bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
phba->vpi_ids[phba->pport->vpi]);
}
command_type = OTHER_COMMAND;
@@ -13080,9 +13262,7 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
} else {
set_bit(xri, phba->sli4_hba.xri_bmask);
phba->sli4_hba.max_cfg_param.xri_used++;
- phba->sli4_hba.xri_count++;
}
-
spin_unlock_irq(&phba->hbalock);
return xri;
}
@@ -13098,7 +13278,6 @@ void
__lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
{
if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) {
- phba->sli4_hba.xri_count--;
phba->sli4_hba.max_cfg_param.xri_used--;
}
}
@@ -13134,46 +13313,45 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba)
uint16_t xri_index;
xri_index = lpfc_sli4_alloc_xri(phba);
- if (xri_index != NO_XRI)
- return xri_index;
-
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2004 Failed to allocate XRI.last XRITAG is %d"
- " Max XRI is %d, Used XRI is %d\n",
- xri_index,
- phba->sli4_hba.max_cfg_param.max_xri,
- phba->sli4_hba.max_cfg_param.xri_used);
- return NO_XRI;
+ if (xri_index == NO_XRI)
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "2004 Failed to allocate XRI.last XRITAG is %d"
+ " Max XRI is %d, Used XRI is %d\n",
+ xri_index,
+ phba->sli4_hba.max_cfg_param.max_xri,
+ phba->sli4_hba.max_cfg_param.xri_used);
+ return xri_index;
}
/**
* lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port.
* @phba: pointer to lpfc hba data structure.
+ * @post_sgl_list: pointer to els sgl entry list.
+ * @count: number of els sgl entries on the list.
*
* This routine is invoked to post a block of driver's sgl pages to the
* HBA using non-embedded mailbox command. No Lock is held. This routine
* is only called when the driver is loading and after all IO has been
* stopped.
**/
-int
-lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
+static int
+lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba,
+ struct list_head *post_sgl_list,
+ int post_cnt)
{
- struct lpfc_sglq *sglq_entry;
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
struct sgl_page_pairs *sgl_pg_pairs;
void *viraddr;
LPFC_MBOXQ_t *mbox;
uint32_t reqlen, alloclen, pg_pairs;
uint32_t mbox_tmo;
- uint16_t xritag_start = 0, lxri = 0;
- int els_xri_cnt, rc = 0;
+ uint16_t xritag_start = 0;
+ int rc = 0;
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
- /* The number of sgls to be posted */
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
-
- reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
+ reqlen = phba->sli4_hba.els_xri_cnt * sizeof(struct sgl_page_pairs) +
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
if (reqlen > SLI4_PAGE_SIZE) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -13203,25 +13381,8 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
sgl_pg_pairs = &sgl->sgl_pg_pairs;
- for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) {
- sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs];
-
- /*
- * Assign the sglq a physical xri only if the driver has not
- * initialized those resources. A port reset only needs
- * the sglq's posted.
- */
- if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) !=
- LPFC_XRI_RSRC_RDY) {
- lxri = lpfc_sli4_next_xritag(phba);
- if (lxri == NO_XRI) {
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
- sglq_entry->sli4_lxritag = lxri;
- sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
- }
-
+ pg_pairs = 0;
+ list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) {
/* Set up the sge entry */
sgl_pg_pairs->sgl_pg0_addr_lo =
cpu_to_le32(putPaddrLow(sglq_entry->phys));
@@ -13236,11 +13397,12 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
if (pg_pairs == 0)
xritag_start = sglq_entry->sli4_xritag;
sgl_pg_pairs++;
+ pg_pairs++;
}
/* Complete initialization and perform endian conversion. */
bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt);
+ bf_set(lpfc_post_sgl_pages_xricnt, sgl, phba->sli4_hba.els_xri_cnt);
sgl->word0 = cpu_to_le32(sgl->word0);
if (!phba->sli4_hba.intr_enable)
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
@@ -13260,183 +13422,6 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
shdr_status, shdr_add_status, rc);
rc = -ENXIO;
}
-
- if (rc == 0)
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
- LPFC_XRI_RSRC_RDY);
- return rc;
-}
-
-/**
- * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port.
- * @phba: pointer to lpfc hba data structure.
- *
- * This routine is invoked to post a block of driver's sgl pages to the
- * HBA using non-embedded mailbox command. No Lock is held. This routine
- * is only called when the driver is loading and after all IO has been
- * stopped.
- **/
-int
-lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba)
-{
- struct lpfc_sglq *sglq_entry;
- struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
- struct sgl_page_pairs *sgl_pg_pairs;
- void *viraddr;
- LPFC_MBOXQ_t *mbox;
- uint32_t reqlen, alloclen, index;
- uint32_t mbox_tmo;
- uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt;
- uint16_t xritag_start = 0, lxri = 0;
- struct lpfc_rsrc_blks *rsrc_blk;
- int cnt, ttl_cnt, rc = 0;
- int loop_cnt;
- uint32_t shdr_status, shdr_add_status;
- union lpfc_sli4_cfg_shdr *shdr;
-
- /* The number of sgls to be posted */
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
-
- reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- if (reqlen > SLI4_PAGE_SIZE) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "2989 Block sgl registration required DMA "
- "size (%d) great than a page\n", reqlen);
- return -ENOMEM;
- }
-
- cnt = 0;
- ttl_cnt = 0;
- post_els_xri_cnt = els_xri_cnt;
- list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
- list) {
- rsrc_start = rsrc_blk->rsrc_start;
- rsrc_size = rsrc_blk->rsrc_size;
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3014 Working ELS Extent start %d, cnt %d\n",
- rsrc_start, rsrc_size);
-
- loop_cnt = min(post_els_xri_cnt, rsrc_size);
- if (loop_cnt < post_els_xri_cnt) {
- post_els_xri_cnt -= loop_cnt;
- ttl_cnt += loop_cnt;
- } else
- ttl_cnt += post_els_xri_cnt;
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- return -ENOMEM;
- /*
- * Allocate DMA memory and set up the non-embedded mailbox
- * command.
- */
- alloclen = lpfc_sli4_config(phba, mbox,
- LPFC_MBOX_SUBSYSTEM_FCOE,
- LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
- reqlen, LPFC_SLI4_MBX_NEMBED);
- if (alloclen < reqlen) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2987 Allocated DMA memory size (%d) "
- "is less than the requested DMA memory "
- "size (%d)\n", alloclen, reqlen);
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
-
- /* Set up the SGL pages in the non-embedded DMA pages */
- viraddr = mbox->sge_array->addr[0];
- sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
- sgl_pg_pairs = &sgl->sgl_pg_pairs;
-
- /*
- * The starting resource may not begin at zero. Control
- * the loop variants via the block resource parameters,
- * but handle the sge pointers with a zero-based index
- * that doesn't get reset per loop pass.
- */
- for (index = rsrc_start;
- index < rsrc_start + loop_cnt;
- index++) {
- sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt];
-
- /*
- * Assign the sglq a physical xri only if the driver
- * has not initialized those resources. A port reset
- * only needs the sglq's posted.
- */
- if (bf_get(lpfc_xri_rsrc_rdy,
- &phba->sli4_hba.sli4_flags) !=
- LPFC_XRI_RSRC_RDY) {
- lxri = lpfc_sli4_next_xritag(phba);
- if (lxri == NO_XRI) {
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- rc = -ENOMEM;
- goto err_exit;
- }
- sglq_entry->sli4_lxritag = lxri;
- sglq_entry->sli4_xritag =
- phba->sli4_hba.xri_ids[lxri];
- }
-
- /* Set up the sge entry */
- sgl_pg_pairs->sgl_pg0_addr_lo =
- cpu_to_le32(putPaddrLow(sglq_entry->phys));
- sgl_pg_pairs->sgl_pg0_addr_hi =
- cpu_to_le32(putPaddrHigh(sglq_entry->phys));
- sgl_pg_pairs->sgl_pg1_addr_lo =
- cpu_to_le32(putPaddrLow(0));
- sgl_pg_pairs->sgl_pg1_addr_hi =
- cpu_to_le32(putPaddrHigh(0));
-
- /* Track the starting physical XRI for the mailbox. */
- if (index == rsrc_start)
- xritag_start = sglq_entry->sli4_xritag;
- sgl_pg_pairs++;
- cnt++;
- }
-
- /* Complete initialization and perform endian conversion. */
- rsrc_blk->rsrc_used += loop_cnt;
- bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt);
- sgl->word0 = cpu_to_le32(sgl->word0);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3015 Post ELS Extent SGL, start %d, "
- "cnt %d, used %d\n",
- xritag_start, loop_cnt, rsrc_blk->rsrc_used);
- if (!phba->sli4_hba.intr_enable)
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
- else {
- mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
- rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
- }
- shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status,
- &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &shdr->response);
- if (rc != MBX_TIMEOUT)
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2988 POST_SGL_BLOCK mailbox "
- "command failed status x%x "
- "add_status x%x mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- rc = -ENXIO;
- goto err_exit;
- }
- if (ttl_cnt >= els_xri_cnt)
- break;
- }
-
- err_exit:
- if (rc == 0)
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
- LPFC_XRI_RSRC_RDY);
return rc;
}
@@ -13452,8 +13437,9 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba)
*
**/
int
-lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
- int cnt)
+lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba,
+ struct list_head *sblist,
+ int count)
{
struct lpfc_scsi_buf *psb;
struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
@@ -13469,7 +13455,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
union lpfc_sli4_cfg_shdr *shdr;
/* Calculate the requested length of the dma memory */
- reqlen = cnt * sizeof(struct sgl_page_pairs) +
+ reqlen = count * sizeof(struct sgl_page_pairs) +
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
if (reqlen > SLI4_PAGE_SIZE) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -13553,169 +13539,6 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
}
/**
- * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port.
- * @phba: pointer to lpfc hba data structure.
- * @sblist: pointer to scsi buffer list.
- * @count: number of scsi buffers on the list.
- *
- * This routine is invoked to post a block of @count scsi sgl pages from a
- * SCSI buffer list @sblist to the HBA using non-embedded mailbox command.
- * No Lock is held.
- *
- **/
-int
-lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist,
- int cnt)
-{
- struct lpfc_scsi_buf *psb = NULL;
- struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
- struct sgl_page_pairs *sgl_pg_pairs;
- void *viraddr;
- LPFC_MBOXQ_t *mbox;
- uint32_t reqlen, alloclen, pg_pairs;
- uint32_t mbox_tmo;
- uint16_t xri_start = 0, scsi_xri_start;
- uint16_t rsrc_range;
- int rc = 0, avail_cnt;
- uint32_t shdr_status, shdr_add_status;
- dma_addr_t pdma_phys_bpl1;
- union lpfc_sli4_cfg_shdr *shdr;
- struct lpfc_rsrc_blks *rsrc_blk;
- uint32_t xri_cnt = 0;
-
- /* Calculate the total requested length of the dma memory */
- reqlen = cnt * sizeof(struct sgl_page_pairs) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- if (reqlen > SLI4_PAGE_SIZE) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "2932 Block sgl registration required DMA "
- "size (%d) great than a page\n", reqlen);
- return -ENOMEM;
- }
-
- /*
- * The use of extents requires the driver to post the sgl headers
- * in multiple postings to meet the contiguous resource assignment.
- */
- psb = list_prepare_entry(psb, sblist, list);
- scsi_xri_start = phba->sli4_hba.scsi_xri_start;
- list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
- list) {
- rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size;
- if (rsrc_range < scsi_xri_start)
- continue;
- else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size)
- continue;
- else
- avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used;
-
- reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- /*
- * Allocate DMA memory and set up the non-embedded mailbox
- * command. The mbox is used to post an SGL page per loop
- * but the DMA memory has a use-once semantic so the mailbox
- * is used and freed per loop pass.
- */
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2933 Failed to allocate mbox cmd "
- "memory\n");
- return -ENOMEM;
- }
- alloclen = lpfc_sli4_config(phba, mbox,
- LPFC_MBOX_SUBSYSTEM_FCOE,
- LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
- reqlen,
- LPFC_SLI4_MBX_NEMBED);
- if (alloclen < reqlen) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2934 Allocated DMA memory size (%d) "
- "is less than the requested DMA memory "
- "size (%d)\n", alloclen, reqlen);
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
-
- /* Get the first SGE entry from the non-embedded DMA memory */
- viraddr = mbox->sge_array->addr[0];
-
- /* Set up the SGL pages in the non-embedded DMA pages */
- sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
- sgl_pg_pairs = &sgl->sgl_pg_pairs;
-
- /* pg_pairs tracks posted SGEs per loop iteration. */
- pg_pairs = 0;
- list_for_each_entry_continue(psb, sblist, list) {
- /* Set up the sge entry */
- sgl_pg_pairs->sgl_pg0_addr_lo =
- cpu_to_le32(putPaddrLow(psb->dma_phys_bpl));
- sgl_pg_pairs->sgl_pg0_addr_hi =
- cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl));
- if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
- pdma_phys_bpl1 = psb->dma_phys_bpl +
- SGL_PAGE_SIZE;
- else
- pdma_phys_bpl1 = 0;
- sgl_pg_pairs->sgl_pg1_addr_lo =
- cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
- sgl_pg_pairs->sgl_pg1_addr_hi =
- cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
- /* Keep the first xri for this extent. */
- if (pg_pairs == 0)
- xri_start = psb->cur_iocbq.sli4_xritag;
- sgl_pg_pairs++;
- pg_pairs++;
- xri_cnt++;
-
- /*
- * Track two exit conditions - the loop has constructed
- * all of the caller's SGE pairs or all available
- * resource IDs in this extent are consumed.
- */
- if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt))
- break;
- }
- rsrc_blk->rsrc_used += pg_pairs;
- bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3016 Post SCSI Extent SGL, start %d, cnt %d "
- "blk use %d\n",
- xri_start, pg_pairs, rsrc_blk->rsrc_used);
- /* Perform endian conversion if necessary */
- sgl->word0 = cpu_to_le32(sgl->word0);
- if (!phba->sli4_hba.intr_enable)
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
- else {
- mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
- rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
- }
- shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &shdr->response);
- if (rc != MBX_TIMEOUT)
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2935 POST_SGL_BLOCK mailbox command "
- "failed status x%x add_status x%x "
- "mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- return -ENXIO;
- }
-
- /* Post only what is requested. */
- if (xri_cnt >= cnt)
- break;
- }
- return rc;
-}
-
-/**
* lpfc_fc_frame_check - Check that this frame is a valid frame to handle
* @phba: pointer to lpfc_hba struct that the frame was received on
* @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
@@ -13839,8 +13662,13 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
uint32_t did = (fc_hdr->fh_d_id[0] << 16 |
fc_hdr->fh_d_id[1] << 8 |
fc_hdr->fh_d_id[2]);
+
if (did == Fabric_DID)
return phba->pport;
+ if ((phba->pport->fc_flag & FC_PT2PT) &&
+ !(phba->link_state == LPFC_HBA_READY))
+ return phba->pport;
+
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
@@ -14133,7 +13961,6 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
return NO_XRI;
}
-
/**
* lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort
* @phba: Pointer to HBA context object.
@@ -14148,7 +13975,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
{
struct lpfc_iocbq *ctiocb = NULL;
struct lpfc_nodelist *ndlp;
- uint16_t oxid, rxid;
+ uint16_t oxid, rxid, xri, lxri;
uint32_t sid, fctl;
IOCB_t *icmd;
int rc;
@@ -14167,8 +13994,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
"SID:x%x\n", oxid, sid);
return;
}
- if (lpfc_sli4_xri_inrange(phba, rxid))
- lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0);
/* Allocate buffer for rsp iocb */
ctiocb = lpfc_sli_get_iocbq(phba);
@@ -14199,13 +14024,24 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
ctiocb->sli4_lxritag = NO_XRI;
ctiocb->sli4_xritag = NO_XRI;
+ if (fctl & FC_FC_EX_CTX)
+ /* Exchange responder sent the abort so we
+ * own the oxid.
+ */
+ xri = oxid;
+ else
+ xri = rxid;
+ lxri = lpfc_sli4_xri_inrange(phba, xri);
+ if (lxri != NO_XRI)
+ lpfc_set_rrq_active(phba, ndlp, lxri,
+ (xri == oxid) ? rxid : oxid, 0);
/* If the oxid maps to the FCP XRI range or if it is out of range,
* send a BLS_RJT. The driver no longer has that exchange.
* Override the IOCB for a BA_RJT.
*/
- if (oxid > (phba->sli4_hba.max_cfg_param.max_xri +
+ if (xri > (phba->sli4_hba.max_cfg_param.max_xri +
phba->sli4_hba.max_cfg_param.xri_base) ||
- oxid > (lpfc_sli4_get_els_iocb_cnt(phba) +
+ xri > (lpfc_sli4_get_els_iocb_cnt(phba) +
phba->sli4_hba.max_cfg_param.xri_base)) {
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT;
bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0);
@@ -14377,7 +14213,15 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
/* Initialize the first IOCB. */
first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
- first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
+
+ /* Check FC Header to see what TYPE of frame we are rcv'ing */
+ if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) {
+ first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX;
+ first_iocbq->iocb.un.rcvels.parmRo =
+ sli4_did_from_fc_hdr(fc_hdr);
+ first_iocbq->iocb.ulpPU = PARM_NPIV_DID;
+ } else
+ first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
first_iocbq->iocb.ulpContext = NO_XRI;
first_iocbq->iocb.unsli3.rcvsli3.ox_id =
be16_to_cpu(fc_hdr->fh_ox_id);
@@ -14507,6 +14351,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
struct fc_frame_header *fc_hdr;
struct lpfc_vport *vport;
uint32_t fcfi;
+ uint32_t did;
/* Process each received buffer */
fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
@@ -14522,12 +14367,32 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
else
fcfi = bf_get(lpfc_rcqe_fcf_id,
&dmabuf->cq_event.cqe.rcqe_cmpl);
+
vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
- if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {
+ if (!vport) {
/* throw out the frame */
lpfc_in_buf_free(phba, &dmabuf->dbuf);
return;
}
+
+ /* d_id this frame is directed to */
+ did = sli4_did_from_fc_hdr(fc_hdr);
+
+ /* vport is registered unless we rcv a FLOGI directed to Fabric_DID */
+ if (!(vport->vpi_state & LPFC_VPI_REGISTERED) &&
+ (did != Fabric_DID)) {
+ /*
+ * Throw out the frame if we are not pt2pt.
+ * The pt2pt protocol allows for discovery frames
+ * to be received without a registered VPI.
+ */
+ if (!(vport->fc_flag & FC_PT2PT) ||
+ (phba->link_state == LPFC_HBA_READY)) {
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ return;
+ }
+ }
+
/* Handle the basic abort sequence (BA_ABTS) event */
if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) {
lpfc_sli4_handle_unsol_abort(vport, dmabuf);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 3290b8e7ab6..2626f58c074 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -68,7 +68,7 @@ struct lpfc_iocbq {
#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */
-#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
+#define LPFC_IO_ON_TXCMPLQ 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_IO_DIF 0x400 /* T10 DIF IO */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index c19d139618b..a4a77080091 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -75,11 +75,19 @@
(fc_hdr)->fh_s_id[1] << 8 | \
(fc_hdr)->fh_s_id[2])
+#define sli4_did_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_d_id[0] << 16 | \
+ (fc_hdr)->fh_d_id[1] << 8 | \
+ (fc_hdr)->fh_d_id[2])
+
#define sli4_fctl_from_fc_hdr(fc_hdr) \
((fc_hdr)->fh_f_ctl[0] << 16 | \
(fc_hdr)->fh_f_ctl[1] << 8 | \
(fc_hdr)->fh_f_ctl[2])
+#define sli4_type_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_type)
+
#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000
enum lpfc_sli4_queue_type {
@@ -493,14 +501,12 @@ struct lpfc_sli4_hba {
uint16_t next_rpi;
uint16_t scsi_xri_max;
uint16_t scsi_xri_cnt;
+ uint16_t els_xri_cnt;
uint16_t scsi_xri_start;
struct list_head lpfc_free_sgl_list;
struct list_head lpfc_sgl_list;
- struct lpfc_sglq **lpfc_els_sgl_array;
struct list_head lpfc_abts_els_sgl_list;
- struct lpfc_scsi_buf **lpfc_scsi_psb_array;
struct list_head lpfc_abts_scsi_buf_list;
- uint32_t total_sglq_bufs;
struct lpfc_sglq **lpfc_sglq_active_list;
struct list_head lpfc_rpi_hdr_list;
unsigned long *rpi_bmask;
@@ -509,7 +515,6 @@ struct lpfc_sli4_hba {
struct list_head lpfc_rpi_blk_list;
unsigned long *xri_bmask;
uint16_t *xri_ids;
- uint16_t xri_count;
struct list_head lpfc_xri_blk_list;
unsigned long *vfi_bmask;
uint16_t *vfi_ids;
@@ -614,11 +619,7 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
-int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba);
-int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba);
int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
-int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *,
- int);
struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 25cefc254b7..59c57a40998 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.30"
+#define LPFC_DRIVER_VERSION "8.3.31"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index e5f416f8042..e8f89264768 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -33,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.06.14-rc1"
-#define MEGASAS_RELDATE "Jan. 6, 2012"
-#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012"
+#define MEGASAS_VERSION "00.00.06.15-rc1"
+#define MEGASAS_RELDATE "Mar. 19, 2012"
+#define MEGASAS_EXT_VERSION "Mon. Mar. 19 17:00:00 PDT 2012"
/*
* Device IDs
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 8b300be4428..dc27598785e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FILE: megaraid_sas_base.c
- * Version : v00.00.06.14-rc1
+ * Version : v00.00.06.15-rc1
*
* Authors: LSI Corporation
* Sreenivas Bagalkote
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 294abb0defa..e3d251a2e26 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -362,15 +362,20 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* assume this IO needs the full row - we'll adjust if not true */
regSize = stripSize;
- /* If IO spans more than 1 strip, fp is not possible
- FP is not possible for writes on non-0 raid levels
- FP is not possible if LD is not capable */
- if (num_strips > 1 || (!isRead && raid->level != 0) ||
- !raid->capability.fpCapable) {
+ /* Check if we can send this I/O via FastPath */
+ if (raid->capability.fpCapable) {
+ if (isRead)
+ io_info->fpOkForIo = (raid->capability.fpReadCapable &&
+ ((num_strips == 1) ||
+ raid->capability.
+ fpReadAcrossStripe));
+ else
+ io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
+ ((num_strips == 1) ||
+ raid->capability.
+ fpWriteAcrossStripe));
+ } else
io_info->fpOkForIo = FALSE;
- } else {
- io_info->fpOkForIo = TRUE;
- }
if (numRows == 1) {
/* single-strip IOs can always lock only the data needed */
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index bfd87fab39a..a610cf1d484 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -634,9 +634,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
fusion->reply_frames_desc_phys;
IOCInitMessage->SystemRequestFrameBaseAddress =
fusion->io_request_frames_phys;
- /* Set to 0 for none or 1 MSI-X vectors */
- IOCInitMessage->HostMSIxVectors = (instance->msix_vectors > 0 ?
- instance->msix_vectors : 0);
+ IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
init_frame = (struct megasas_init_frame *)cmd->frame;
memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index a01f0aa66f2..a80f3220c64 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.22
+ * mpi2.h Version: 02.00.23
*
* Version History
* ---------------
@@ -71,6 +71,7 @@
* 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
* 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
* 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -96,7 +97,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x16)
+#define MPI2_HEADER_VERSION_UNIT (0x17)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -480,7 +481,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
- Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
+Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 3a023dad77a..737fa8cfb54 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.21
+ * mpi2_cnfg.h Version: 02.00.22
*
* Version History
* ---------------
@@ -146,7 +146,9 @@
* Added SpinupFlags field containing a Disable Spin-up
* bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of
* SAS IO Unit Page 4.
-
+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
+ * Added UEFIVersion field to BIOS Page 1 and defined new
+ * BiosOptions bits.
* --------------------------------------------------------------------------
*/
@@ -1131,9 +1133,10 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_6
} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
-#define MPI2_IOCPAGE6_PAGEVERSION (0x04)
+#define MPI2_IOCPAGE6_PAGEVERSION (0x05)
/* defines for IOC Page 6 CapabilitiesFlags */
+#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004)
@@ -1204,24 +1207,29 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_8
typedef struct _MPI2_CONFIG_PAGE_BIOS_1
{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 BiosOptions; /* 0x04 */
- U32 IOCSettings; /* 0x08 */
- U32 Reserved1; /* 0x0C */
- U32 DeviceSettings; /* 0x10 */
- U16 NumberOfDevices; /* 0x14 */
- U16 Reserved2; /* 0x16 */
- U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
- U16 IOTimeoutSequential; /* 0x1A */
- U16 IOTimeoutOther; /* 0x1C */
- U16 IOTimeoutBlockDevicesRM; /* 0x1E */
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U32 BiosOptions; /* 0x04 */
+ U32 IOCSettings; /* 0x08 */
+ U32 Reserved1; /* 0x0C */
+ U32 DeviceSettings; /* 0x10 */
+ U16 NumberOfDevices; /* 0x14 */
+ U16 UEFIVersion; /* 0x16 */
+ U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
+ U16 IOTimeoutSequential; /* 0x1A */
+ U16 IOTimeoutOther; /* 0x1C */
+ U16 IOTimeoutBlockDevicesRM; /* 0x1E */
} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
-#define MPI2_BIOSPAGE1_PAGEVERSION (0x04)
+#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
/* values for BIOS Page 1 BiosOptions field */
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
+#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
+#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004)
+
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
/* values for BIOS Page 1 IOCSettings field */
#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000)
@@ -1248,6 +1256,13 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1
#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001)
+/* defines for BIOS Page 1 UEFIVersion field */
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00)
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0)
+
+
/* BIOS Page 2 */
@@ -2216,6 +2231,27 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
+/* SAS IO Unit Page 16 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U64 TimeStamp; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 FastPathPendedRequests; /* 0x18 */
+ U32 FastPathUnPendedRequests; /* 0x1C */
+ U32 FastPathHostRequestStarts; /* 0x20 */
+ U32 FastPathFirmwareRequestStarts; /* 0x24 */
+ U32 FastPathHostCompletions; /* 0x28 */
+ U32 FastPathFirmwareCompletions; /* 0x2C */
+ U32 NonFastPathRequestStarts; /* 0x30 */
+ U32 NonFastPathHostCompletions; /* 0x30 */
+} MPI2_CONFIG_PAGE_SASIOUNIT16,
+MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16,
+Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t;
+
+#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00)
+
/****************************************************************************
* SAS Expander Config Pages
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 8a59a772fdf..6102ef2cb2d 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -699,6 +699,11 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u16 ioc_status;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return;
+ }
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
@@ -930,16 +935,18 @@ _base_interrupt(int irq, void *bus_id)
else if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
goto next;
- if (smid)
+ if (smid) {
cb_idx = _base_get_cb_idx(ioc, smid);
- if (smid && cb_idx != 0xFF) {
- rc = mpt_callbacks[cb_idx](ioc, smid, msix_index,
- reply);
+ if ((likely(cb_idx < MPT_MAX_CALLBACKS))
+ && (likely(mpt_callbacks[cb_idx] != NULL))) {
+ rc = mpt_callbacks[cb_idx](ioc, smid,
+ msix_index, reply);
if (reply)
- _base_display_reply_info(ioc, smid, msix_index,
- reply);
+ _base_display_reply_info(ioc, smid,
+ msix_index, reply);
if (rc)
mpt2sas_base_free_smid(ioc, smid);
+ }
}
if (!smid)
_base_async_event(ioc, msix_index, reply);
@@ -3343,7 +3350,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
}
pfacts = &ioc->pfacts[port];
- memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t));
+ memset(pfacts, 0, sizeof(struct mpt2sas_port_facts));
pfacts->PortNumber = mpi_reply.PortNumber;
pfacts->VP_ID = mpi_reply.VP_ID;
pfacts->VF_ID = mpi_reply.VF_ID;
@@ -3385,7 +3392,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
facts = &ioc->facts;
- memset(facts, 0, sizeof(Mpi2IOCFactsReply_t));
+ memset(facts, 0, sizeof(struct mpt2sas_facts));
facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
facts->VP_ID = mpi_reply.VP_ID;
@@ -4153,7 +4160,8 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (ioc->is_driver_loading) {
if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
== 0x80) {
- hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 &
+ hide_flag = (u8) (
+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
MFG_PAGE10_HIDE_SSDS_MASK);
if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
ioc->mfg_pg10_hide_flag = hide_flag;
@@ -4262,7 +4270,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
+ sizeof(struct mpt2sas_port_facts), GFP_KERNEL);
if (!ioc->pfacts) {
r = -ENOMEM;
goto out_free_resources;
@@ -4279,7 +4287,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
init_waitqueue_head(&ioc->reset_wq);
-
/* allocate memory pd handle bitmask list */
ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
if (ioc->facts.MaxDevHandle % 8)
@@ -4290,7 +4297,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
r = -ENOMEM;
goto out_free_resources;
}
-
+ ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
+ GFP_KERNEL);
+ if (!ioc->blocking_handles) {
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
ioc->fwfault_debug = mpt2sas_fwfault_debug;
/* base internal command bits */
@@ -4377,6 +4389,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
if (ioc->is_warpdrive)
kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
+ kfree(ioc->blocking_handles);
kfree(ioc->tm_cmds.reply);
kfree(ioc->transport_cmds.reply);
kfree(ioc->scsih_cmds.reply);
@@ -4418,6 +4431,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
if (ioc->is_warpdrive)
kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
+ kfree(ioc->blocking_handles);
kfree(ioc->pfacts);
kfree(ioc->ctl_cmds.reply);
kfree(ioc->ctl_cmds.sense);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index c7459fdc06c..b6dd3a5de7f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "12.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 12
+#define MPT2SAS_DRIVER_VERSION "13.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 13
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -720,6 +720,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
* @io_missing_delay: time for IO completed by fw when PDR enabled
* @device_missing_delay: time for device missing by fw when PDR enabled
* @sas_id : used for setting volume target IDs
+ * @blocking_handles: bitmask used to identify which devices need blocking
* @pd_handles : bitmask for PD handles
* @pd_handles_sz : size of pd_handle bitmask
* @config_page_sz: config page size
@@ -889,7 +890,7 @@ struct MPT2SAS_ADAPTER {
u8 io_missing_delay;
u16 device_missing_delay;
int sas_id;
-
+ void *blocking_handles;
void *pd_handles;
u16 pd_handles_sz;
@@ -1058,7 +1059,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address);
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 3b9a28efea8..49bdd2dc845 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -620,11 +620,10 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
* @ioc: per adapter object
* @karg - (struct mpt2_ioctl_command)
* @mf - pointer to mf in user space
- * @state - NON_BLOCKING or BLOCKING
*/
static long
-_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
+_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg,
+ void __user *mf)
{
MPI2RequestHeader_t *mpi_request = NULL, *request;
MPI2DefaultReply_t *mpi_reply;
@@ -647,11 +646,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
issue_reset = 0;
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
@@ -871,8 +865,16 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
if (smp_request->PassthroughFlags &
MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
data = (u8 *)&smp_request->SGL;
- else
+ else {
+ if (unlikely(data_out == NULL)) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ mpt2sas_base_free_smid(ioc, smid);
+ ret = -EINVAL;
+ goto out;
+ }
data = data_out;
+ }
if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
ioc->ioc_link_reset_in_progress = 1;
@@ -985,7 +987,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ret = -ENODATA;
if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+ mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
"= (0x%04x)\n", ioc->name,
le16_to_cpu(mpi_request->FunctionDependent1));
@@ -1013,27 +1016,24 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
kfree(mpi_request);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
}
/**
* _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_getiocinfo(void __user *arg)
+_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_iocinfo karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1069,21 +1069,19 @@ _ctl_getiocinfo(void __user *arg)
/**
* _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventquery(void __user *arg)
+_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventquery karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1102,21 +1100,19 @@ _ctl_eventquery(void __user *arg)
/**
* _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventenable(void __user *arg)
+_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventenable karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1142,13 +1138,13 @@ _ctl_eventenable(void __user *arg)
/**
* _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventreport(void __user *arg)
+_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventreport karg;
- struct MPT2SAS_ADAPTER *ioc;
u32 number_bytes, max_events, max;
struct mpt2_ioctl_eventreport __user *uarg = arg;
@@ -1157,8 +1153,6 @@ _ctl_eventreport(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1188,13 +1182,13 @@ _ctl_eventreport(void __user *arg)
/**
* _ctl_do_reset - main handler for MPT2HARDRESET opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_do_reset(void __user *arg)
+_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_diag_reset karg;
- struct MPT2SAS_ADAPTER *ioc;
int retval;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1202,8 +1196,6 @@ _ctl_do_reset(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
if (ioc->shost_recovery || ioc->pci_error_recovery ||
ioc->is_driver_loading)
@@ -1292,13 +1284,13 @@ _ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,
/**
* _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_btdh_mapping(void __user *arg)
+_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_btdh_mapping karg;
- struct MPT2SAS_ADAPTER *ioc;
int rc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1306,8 +1298,6 @@ _ctl_btdh_mapping(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1576,17 +1566,16 @@ mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
/**
* _ctl_diag_register - application register with driver
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*
* This will allow the driver to setup any required buffers that will be
* needed by firmware to communicate with the driver.
*/
static long
-_ctl_diag_register(void __user *arg, enum block_state state)
+_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_register karg;
- struct MPT2SAS_ADAPTER *ioc;
long rc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1594,30 +1583,23 @@ _ctl_diag_register(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
rc = _ctl_diag_register_2(ioc, &karg);
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_unregister - application unregister with driver
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*
* This will allow the driver to cleanup any memory allocated for diag
* messages and to free up any resources.
*/
static long
-_ctl_diag_unregister(void __user *arg)
+_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_unregister karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
dma_addr_t request_data_dma;
u32 request_data_sz;
@@ -1628,8 +1610,6 @@ _ctl_diag_unregister(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1678,6 +1658,7 @@ _ctl_diag_unregister(void __user *arg)
/**
* _ctl_diag_query - query relevant info associated with diag buffers
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*
* The application will send only buffer_type and unique_id. Driver will
@@ -1685,10 +1666,9 @@ _ctl_diag_unregister(void __user *arg)
* 0x00, the driver will return info specified by Buffer Type.
*/
static long
-_ctl_diag_query(void __user *arg)
+_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_query karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int i;
u8 buffer_type;
@@ -1698,8 +1678,6 @@ _ctl_diag_query(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1866,17 +1844,15 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
/**
* _ctl_diag_release - request to send Diag Release Message to firmware
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*
* This allows ownership of the specified buffer to returned to the driver,
* allowing an application to read the buffer without fear that firmware is
* overwritting information in the buffer.
*/
static long
-_ctl_diag_release(void __user *arg, enum block_state state)
+_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_release karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int rc;
u8 buffer_type;
@@ -1887,8 +1863,6 @@ _ctl_diag_release(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1942,32 +1916,25 @@ _ctl_diag_release(void __user *arg, enum block_state state)
return 0;
}
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
rc = _ctl_send_release(ioc, buffer_type, &issue_reset);
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_read_buffer - request for copy of the diag buffer
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*/
static long
-_ctl_diag_read_buffer(void __user *arg, enum block_state state)
+_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_read_buffer karg;
struct mpt2_diag_read_buffer __user *uarg = arg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data, *diag_data;
Mpi2DiagBufferPostRequest_t *mpi_request;
Mpi2DiagBufferPostReply_t *mpi_reply;
@@ -1983,8 +1950,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -2055,10 +2020,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
}
/* Get a free request frame and save the message context.
*/
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
@@ -2139,115 +2100,170 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
out:
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
+
+#ifdef CONFIG_COMPAT
+/**
+ * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
+ * @ioc: per adapter object
+ * @cmd - ioctl opcode
+ * @arg - (struct mpt2_ioctl_command32)
+ *
+ * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
+ */
+static long
+_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd,
+ void __user *arg)
+{
+ struct mpt2_ioctl_command32 karg32;
+ struct mpt2_ioctl_command32 __user *uarg;
+ struct mpt2_ioctl_command karg;
+
+ if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
+ return -EINVAL;
+
+ uarg = (struct mpt2_ioctl_command32 __user *) arg;
+
+ if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+
+ memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
+ karg.hdr.ioc_number = karg32.hdr.ioc_number;
+ karg.hdr.port_number = karg32.hdr.port_number;
+ karg.hdr.max_data_size = karg32.hdr.max_data_size;
+ karg.timeout = karg32.timeout;
+ karg.max_reply_bytes = karg32.max_reply_bytes;
+ karg.data_in_size = karg32.data_in_size;
+ karg.data_out_size = karg32.data_out_size;
+ karg.max_sense_bytes = karg32.max_sense_bytes;
+ karg.data_sge_offset = karg32.data_sge_offset;
+ karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
+ karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
+ karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
+ karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
+ return _ctl_do_mpt_command(ioc, karg, &uarg->mf);
+}
+#endif
+
/**
* _ctl_ioctl_main - main ioctl entry point
* @file - (struct file)
* @cmd - ioctl opcode
* @arg -
+ * compat - handles 32 bit applications in 64bit os
*/
static long
-_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
+_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
+ u8 compat)
{
+ struct MPT2SAS_ADAPTER *ioc;
+ struct mpt2_ioctl_header ioctl_header;
enum block_state state;
long ret = -EINVAL;
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
- BLOCKING;
+ /* get IOCTL header */
+ if (copy_from_user(&ioctl_header, (char __user *)arg,
+ sizeof(struct mpt2_ioctl_header))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+
+ if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
+ return -ENODEV;
+ if (ioc->shost_recovery || ioc->pci_error_recovery ||
+ ioc->is_driver_loading)
+ return -EAGAIN;
+
+ state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
+ if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+ return -EAGAIN;
+ else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+ return -ERESTARTSYS;
switch (cmd) {
case MPT2IOCINFO:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
- ret = _ctl_getiocinfo(arg);
+ ret = _ctl_getiocinfo(ioc, arg);
break;
+#ifdef CONFIG_COMPAT
+ case MPT2COMMAND32:
+#endif
case MPT2COMMAND:
{
- struct mpt2_ioctl_command karg;
struct mpt2_ioctl_command __user *uarg;
- struct MPT2SAS_ADAPTER *ioc;
-
+ struct mpt2_ioctl_command karg;
+#ifdef CONFIG_COMPAT
+ if (compat) {
+ ret = _ctl_compat_mpt_command(ioc, cmd, arg);
+ break;
+ }
+#endif
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
- return -EFAULT;
+ ret = -EFAULT;
+ break;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
- !ioc)
- return -ENODEV;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
-
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
uarg = arg;
- ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
+ ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
}
break;
}
case MPT2EVENTQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
- ret = _ctl_eventquery(arg);
+ ret = _ctl_eventquery(ioc, arg);
break;
case MPT2EVENTENABLE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
- ret = _ctl_eventenable(arg);
+ ret = _ctl_eventenable(ioc, arg);
break;
case MPT2EVENTREPORT:
- ret = _ctl_eventreport(arg);
+ ret = _ctl_eventreport(ioc, arg);
break;
case MPT2HARDRESET:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
- ret = _ctl_do_reset(arg);
+ ret = _ctl_do_reset(ioc, arg);
break;
case MPT2BTDHMAPPING:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
- ret = _ctl_btdh_mapping(arg);
+ ret = _ctl_btdh_mapping(ioc, arg);
break;
case MPT2DIAGREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
- ret = _ctl_diag_register(arg, state);
+ ret = _ctl_diag_register(ioc, arg);
break;
case MPT2DIAGUNREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
- ret = _ctl_diag_unregister(arg);
+ ret = _ctl_diag_unregister(ioc, arg);
break;
case MPT2DIAGQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
- ret = _ctl_diag_query(arg);
+ ret = _ctl_diag_query(ioc, arg);
break;
case MPT2DIAGRELEASE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
- ret = _ctl_diag_release(arg, state);
+ ret = _ctl_diag_release(ioc, arg);
break;
case MPT2DIAGREADBUFFER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
- ret = _ctl_diag_read_buffer(arg, state);
+ ret = _ctl_diag_read_buffer(ioc, arg);
break;
default:
- {
- struct mpt2_ioctl_command karg;
- struct MPT2SAS_ADAPTER *ioc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
- !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
"unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
break;
}
- }
+
+ mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
}
@@ -2262,66 +2278,11 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- mutex_lock(&_ctl_mutex);
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
- mutex_unlock(&_ctl_mutex);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
return ret;
}
-
#ifdef CONFIG_COMPAT
/**
- * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg - (struct mpt2_ioctl_command32)
- *
- * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
- */
-static long
-_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
-{
- struct mpt2_ioctl_command32 karg32;
- struct mpt2_ioctl_command32 __user *uarg;
- struct mpt2_ioctl_command karg;
- struct MPT2SAS_ADAPTER *ioc;
- enum block_state state;
-
- if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
- return -EINVAL;
-
- uarg = (struct mpt2_ioctl_command32 __user *) arg;
-
- if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
-
- memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
- karg.hdr.ioc_number = karg32.hdr.ioc_number;
- karg.hdr.port_number = karg32.hdr.port_number;
- karg.hdr.max_data_size = karg32.hdr.max_data_size;
- karg.timeout = karg32.timeout;
- karg.max_reply_bytes = karg32.max_reply_bytes;
- karg.data_in_size = karg32.data_in_size;
- karg.data_out_size = karg32.data_out_size;
- karg.max_sense_bytes = karg32.max_sense_bytes;
- karg.data_sge_offset = karg32.data_sge_offset;
- karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
- karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
- karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
- karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
- return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
-}
-
-/**
* _ctl_ioctl_compat - main ioctl entry point (compat)
* @file -
* @cmd -
@@ -2334,12 +2295,7 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
- mutex_lock(&_ctl_mutex);
- if (cmd == MPT2COMMAND32)
- ret = _ctl_compat_mpt_command(file, cmd, arg);
- else
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
- mutex_unlock(&_ctl_mutex);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
return ret;
}
#endif
@@ -2884,7 +2840,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
struct mpt2_diag_register diag_register;
u8 issue_reset = 0;
- if (sscanf(buf, "%s", str) != 1)
+ if (sscanf(buf, "%9s", str) != 1)
return -EINVAL;
if (!strcmp(str, "post")) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index d953a57e779..76973e8ca4b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -579,14 +579,12 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device->sas_address)) {
- list_del(&sas_device->list);
- kfree(sas_device);
- }
+ list_del(&sas_device->list);
+ kfree(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
+
/**
* _scsih_sas_device_add - insert sas_device to the list.
* @ioc: per adapter object
@@ -645,8 +643,8 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
_scsih_determine_boot_device(ioc, sas_device, 0);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
/**
@@ -755,7 +753,6 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
* @ioc: per adapter object
* @raid_device: raid_device object
*
- * This is removed from the raid_device_list link list.
*/
static void
_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
@@ -765,7 +762,6 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->raid_device_lock, flags);
list_del(&raid_device->list);
- memset(raid_device, 0, sizeof(struct _raid_device));
kfree(raid_device);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
@@ -1199,10 +1195,10 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_device_priv_data->sas_target->sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device && sas_device->device_info &
MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata:
@@ -1299,7 +1295,8 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->handle = raid_device->handle;
sas_target_priv_data->sas_address = raid_device->wwid;
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- sas_target_priv_data->raid_device = raid_device;
+ if (ioc->is_warpdrive)
+ sas_target_priv_data->raid_device = raid_device;
raid_device->starget = starget;
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
@@ -1465,12 +1462,12 @@ _scsih_slave_destroy(struct scsi_device *sdev)
/**
* _scsih_display_sata_capabilities - sata capabilities
* @ioc: per adapter object
- * @sas_device: the sas_device object
+ * @handle: device handle
* @sdev: scsi device struct
*/
static void
_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device, struct scsi_device *sdev)
+ u16 handle, struct scsi_device *sdev)
{
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
@@ -1479,7 +1476,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
u32 device_info;
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return;
@@ -1537,27 +1534,40 @@ _scsih_get_resync(struct device *dev)
Mpi2RaidVolPage0_t vol_pg0;
Mpi2ConfigReply_t mpi_reply;
u32 volume_status_flags;
- u8 percent_complete = 0;
+ u8 percent_complete;
+ u16 handle;
+
+ percent_complete = 0;
+ handle = 0;
+ if (ioc->is_warpdrive)
+ goto out;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
+ if (raid_device) {
+ handle = raid_device->handle;
+ percent_complete = raid_device->percent_complete;
+ }
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device || ioc->is_warpdrive)
+ if (!handle)
goto out;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
+ percent_complete = 0;
goto out;
}
volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
- percent_complete = raid_device->percent_complete;
+ if (!(volume_status_flags &
+ MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
+ percent_complete = 0;
+
out:
raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
}
@@ -1577,17 +1587,20 @@ _scsih_get_state(struct device *dev)
Mpi2ConfigReply_t mpi_reply;
u32 volstate;
enum raid_state state = RAID_STATE_UNKNOWN;
+ u16 handle = 0;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
+ if (raid_device)
+ handle = raid_device->handle;
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device)
goto out;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -1620,14 +1633,14 @@ _scsih_get_state(struct device *dev)
/**
* _scsih_set_level - set raid level
* @sdev: scsi device struct
- * @raid_device: raid_device object
+ * @volume_type: volume type
*/
static void
-_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
+_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
{
enum raid_level level = RAID_LEVEL_UNKNOWN;
- switch (raid_device->volume_type) {
+ switch (volume_type) {
case MPI2_RAID_VOL_TYPE_RAID0:
level = RAID_LEVEL_0;
break;
@@ -1722,6 +1735,7 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
struct _raid_device *raid_device;
u16 handle;
u16 ioc_status;
+ unsigned long flags;
handle = 0xFFFF;
while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
@@ -1731,9 +1745,11 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(vol_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
if (raid_device)
raid_device->direct_io_enabled = 0;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
return;
}
@@ -1838,7 +1854,8 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
&pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
vol_pg0->PhysDisk[count].PhysDiskNum) ||
- pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) {
+ le16_to_cpu(pd_pg0.DevHandle) ==
+ MPT2SAS_INVALID_DEVICE_HANDLE) {
printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
"disabled for the drive with handle(0x%04x) member"
"handle retrieval failed for member number=%d\n",
@@ -1968,19 +1985,21 @@ _scsih_slave_configure(struct scsi_device *sdev)
u8 ssp_target = 0;
char *ds = "";
char *r_level = "";
+ u16 handle, volume_handle = 0;
+ u64 volume_wwid = 0;
qdepth = 1;
sas_device_priv_data = sdev->hostdata;
sas_device_priv_data->configured_lun = 1;
sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
sas_target_priv_data = sas_device_priv_data->sas_target;
+ handle = sas_target_priv_data->handle;
/* raid volume handling */
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc,
- sas_target_priv_data->handle);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device) {
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
@@ -1989,8 +2008,6 @@ _scsih_slave_configure(struct scsi_device *sdev)
return 1;
}
- _scsih_get_volume_capabilities(ioc, raid_device);
-
if (_scsih_get_volume_capabilities(ioc, raid_device)) {
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
"failure at %s:%d/%s()!\n", ioc->name, __FILE__,
@@ -2058,68 +2075,67 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
/* raid transport support */
if (!ioc->is_warpdrive)
- _scsih_set_level(sdev, raid_device);
+ _scsih_set_level(sdev, raid_device->volume_type);
return 0;
}
/* non-raid handling */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device_priv_data->sas_target->sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device) {
- if (sas_target_priv_data->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- if (mpt2sas_config_get_volume_handle(ioc,
- sas_device->handle, &sas_device->volume_handle)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- if (sas_device->volume_handle &&
- mpt2sas_config_get_volume_wwid(ioc,
- sas_device->volume_handle,
- &sas_device->volume_wwid)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ if (mpt2sas_config_get_volume_handle(ioc, handle,
+ &volume_handle)) {
+ dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+ "failure at %s:%d/%s()!\n", ioc->name,
+ __FILE__, __LINE__, __func__));
+ return 1;
}
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ssp_target = 1;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_STP_TARGET)
- ds = "STP";
- else if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
+ if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
+ volume_handle, &volume_wwid)) {
+ dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+ "failure at %s:%d/%s()!\n", ioc->name,
+ __FILE__, __LINE__, __func__));
+ return 1;
}
+ }
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
- ds, sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy,
- (unsigned long long)sas_device->device_name);
- sdev_printk(KERN_INFO, sdev, "%s: "
- "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
- (unsigned long long) sas_device->enclosure_logical_id,
- sas_device->slot);
-
- if (!ssp_target)
- _scsih_display_sata_capabilities(ioc, sas_device, sdev);
- } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device_priv_data->sas_target->sas_address);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
+ __LINE__, __func__));
return 1;
}
+ sas_device->volume_handle = volume_handle;
+ sas_device->volume_wwid = volume_wwid;
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+ qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
+ ssp_target = 1;
+ ds = "SSP";
+ } else {
+ qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
+ ds = "STP";
+ else if (sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ ds = "SATA";
+ }
+ sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
+ "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
+ ds, sas_device->handle,
+ (unsigned long long)sas_device->sas_address,
+ sas_device->phy,
+ (unsigned long long)sas_device->device_name);
+ sdev_printk(KERN_INFO, sdev, "%s: "
+ "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
+ (unsigned long long) sas_device->enclosure_logical_id,
+ sas_device->slot);
+
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!ssp_target)
+ _scsih_display_sata_capabilities(ioc, handle, sdev);
+
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
@@ -2899,7 +2915,7 @@ _scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
* During device pull we need to appropiately set the sdev state.
*/
static void
-_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct scsi_device *sdev;
@@ -2910,10 +2926,12 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
continue;
if (!sas_device_priv_data->block)
continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
+ if (sas_device_priv_data->sas_target->sas_address ==
+ sas_address) {
dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
MPT2SAS_INFO_FMT "SDEV_RUNNING: "
- "handle(0x%04x)\n", ioc->name, handle));
+ "sas address(0x%016llx)\n", ioc->name,
+ (unsigned long long)sas_address));
sas_device_priv_data->block = 0;
scsi_internal_device_unblock(sdev);
}
@@ -3006,10 +3024,10 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
sas_device =
mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
+ if (sas_device)
+ set_bit(sas_device->handle,
+ ioc->blocking_handles);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- continue;
- _scsih_block_io_device(ioc, sas_device->handle);
}
}
@@ -3020,12 +3038,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
SAS_FANOUT_EXPANDER_DEVICE) {
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_sibling =
mpt2sas_scsih_expander_find_by_sas_address(
ioc, mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_block_io_to_children_attached_to_ex(ioc,
expander_sibling);
}
@@ -3124,7 +3139,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle,
(unsigned long long)sas_address));
- _scsih_ublock_io_device(ioc, handle);
+ _scsih_ublock_io_device(ioc, sas_address);
sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
}
@@ -3174,16 +3189,19 @@ static u8
_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u8 msix_index, u32 reply)
{
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2SasIoUnitControlReply_t *mpi_reply =
mpt2sas_base_get_reply_virt_addr(ioc, reply);
-#endif
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "sc_complete:handle(0x%04x), (open) "
- "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
- le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo)));
+ if (likely(mpi_reply)) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "sc_complete:handle(0x%04x), (open) "
+ "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ } else {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ }
return 1;
}
@@ -3262,7 +3280,11 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
"progress!\n", __func__, ioc->name));
return 1;
}
-
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
@@ -3325,7 +3347,11 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
"operational\n", __func__, ioc->name));
return 1;
}
-
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
@@ -3441,14 +3467,20 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
_scsih_block_io_to_children_attached_directly(ioc, event_data);
return;
}
-
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
- || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
+ if (event_data->ExpStatus ==
+ MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
+ /* put expander attached devices into blocking state */
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
expander_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ do {
+ handle = find_first_bit(ioc->blocking_handles,
+ ioc->facts.MaxDevHandle);
+ if (handle < ioc->facts.MaxDevHandle)
+ _scsih_block_io_device(ioc, handle);
+ } while (test_and_clear_bit(handle, ioc->blocking_handles));
} else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
_scsih_block_io_to_children_attached_directly(ioc, event_data);
@@ -4446,8 +4478,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
!= MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
ioc->scsi_lookup[smid - 1].scmd = scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
_scsih_scsi_direct_io_set(ioc, smid, 0);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
mpi_request->DevHandle =
cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -5020,13 +5052,11 @@ mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
- if (!sas_expander) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- list_del(&sas_expander->list);
+ if (sas_expander)
+ list_del(&sas_expander->list);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- _scsih_expander_node_remove(ioc, sas_expander);
+ if (sas_expander)
+ _scsih_expander_node_remove(ioc, sas_expander);
}
/**
@@ -5106,6 +5136,7 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
struct MPT2SAS_TARGET *sas_target_priv_data;
u32 device_info;
+
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
return;
@@ -5139,21 +5170,24 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
sas_target_priv_data->handle = handle;
sas_device->handle = handle;
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
/* check if device is present */
if (!(le16_to_cpu(sas_device_pg0.Flags) &
MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
printk(MPT2SAS_ERR_FMT "device is not present "
"handle(0x%04x), flags!!!\n", ioc->name, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
}
/* check if there were any issues with discovery */
if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
+ sas_device_pg0.AccessStatus)) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
- _scsih_ublock_io_device(ioc, handle);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_ublock_io_device(ioc, sas_address);
}
@@ -5280,54 +5314,71 @@ static void
_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
struct _sas_device *sas_device)
{
- struct _sas_device sas_device_backup;
struct MPT2SAS_TARGET *sas_target_priv_data;
- if (!sas_device)
- return;
-
- memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
- _scsih_sas_device_remove(ioc, sas_device);
-
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device_backup.handle, (unsigned long long)
- sas_device_backup.sas_address));
+ sas_device->handle, (unsigned long long)
+ sas_device->sas_address));
- if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
- sas_target_priv_data = sas_device_backup.starget->hostdata;
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
sas_target_priv_data->deleted = 1;
- _scsih_ublock_io_device(ioc, sas_device_backup.handle);
+ _scsih_ublock_io_device(ioc, sas_device->sas_address);
sas_target_priv_data->handle =
MPT2SAS_INVALID_DEVICE_HANDLE;
}
- _scsih_ublock_io_device(ioc, sas_device_backup.handle);
-
if (!ioc->hide_drives)
mpt2sas_transport_port_remove(ioc,
- sas_device_backup.sas_address,
- sas_device_backup.sas_address_parent);
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
- (unsigned long long) sas_device_backup.sas_address);
+ "(0x%016llx)\n", ioc->name, sas_device->handle,
+ (unsigned long long) sas_device->sas_address);
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device_backup.handle, (unsigned long long)
- sas_device_backup.sas_address));
+ sas_device->handle, (unsigned long long)
+ sas_device->sas_address));
+ kfree(sas_device);
+}
+/**
+ * _scsih_device_remove_by_handle - removing device object by handle
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_device *sas_device;
+ unsigned long flags;
+
+ if (ioc->shost_recovery)
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device)
+ list_del(&sas_device->list);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device)
+ _scsih_remove_device(ioc, sas_device);
}
/**
- * mpt2sas_device_remove - removing device object
+ * mpt2sas_device_remove_by_sas_address - removing device object by sas address
* @ioc: per adapter object
- * @sas_address: expander sas_address
+ * @sas_address: device sas_address
*
* Return nothing.
*/
void
-mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address)
{
struct _sas_device *sas_device;
unsigned long flags;
@@ -5338,14 +5389,12 @@ mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (sas_device)
+ list_del(&sas_device->list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_remove_device(ioc, sas_device);
+ if (sas_device)
+ _scsih_remove_device(ioc, sas_device);
}
-
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
@@ -5442,7 +5491,6 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number, max_phys;
struct _sas_node *sas_expander;
- struct _sas_device *sas_device;
u64 sas_address;
unsigned long flags;
u8 link_rate, prev_link_rate;
@@ -5477,15 +5525,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
parent_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (sas_expander) {
sas_address = sas_expander->sas_address;
max_phys = sas_expander->num_phys;
} else if (parent_handle < ioc->sas_hba.num_phys) {
sas_address = ioc->sas_hba.sas_address;
max_phys = ioc->sas_hba.num_phys;
- } else
+ } else {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
@@ -5540,16 +5590,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock,
- flags);
- break;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_remove_device(ioc, sas_device);
+ _scsih_device_remove_by_handle(ioc, handle);
break;
}
}
@@ -5672,20 +5713,24 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
sas_address = le64_to_cpu(event_data->SASAddress);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device || !sas_device->starget)
+ if (!sas_device || !sas_device->starget) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
+ }
target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data)
+ if (!target_priv_data) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
+ }
if (event_data->ReasonCode ==
MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
target_priv_data->tm_busy = 1;
else
target_priv_data->tm_busy = 0;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -5950,30 +5995,6 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
}
/**
- * _scsih_reprobe_target - reprobing target
- * @starget: scsi target struct
- * @no_uld_attach: sdev->no_uld_attach flag setting
- *
- * Note: no_uld_attach flag determines whether the disk device is attached
- * to block layer. A value of `1` means to not attach.
- **/
-static void
-_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
-
- if (starget == NULL)
- return;
- sas_target_priv_data = starget->hostdata;
- if (no_uld_attach)
- sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
- else
- sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-
- starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
- _scsih_reprobe_lun);
-}
-/**
* _scsih_sas_volume_add - add new volume
* @ioc: per adapter object
* @element: IR config element data
@@ -6024,8 +6045,11 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
raid_device->id, 0);
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
- } else
+ } else {
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
_scsih_determine_boot_device(ioc, raid_device, 1);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ }
}
/**
@@ -6042,21 +6066,25 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
struct _raid_device *raid_device;
unsigned long flags;
struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct scsi_target *starget = NULL;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device)
- return;
- if (raid_device->starget) {
- sas_target_priv_data = raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- scsi_remove_target(&raid_device->starget->dev);
+ if (raid_device) {
+ if (raid_device->starget) {
+ starget = raid_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ }
+ printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+ "(0x%016llx)\n", ioc->name, raid_device->handle,
+ (unsigned long long) raid_device->wwid);
+ list_del(&raid_device->list);
+ kfree(raid_device);
}
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- _scsih_raid_device_remove(ioc, raid_device);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ if (starget)
+ scsi_remove_target(&starget->dev);
}
/**
@@ -6072,20 +6100,31 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
+ struct scsi_target *starget = NULL;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device->volume_handle = 0;
+ sas_device->volume_wwid = 0;
+ clear_bit(handle, ioc->pd_handles);
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->flags &=
+ ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+ }
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
/* exposing raid component */
- sas_device->volume_handle = 0;
- sas_device->volume_wwid = 0;
- clear_bit(handle, ioc->pd_handles);
- _scsih_reprobe_target(sas_device->starget, 0);
+ if (starget)
+ starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
}
/**
@@ -6101,23 +6140,38 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
+ struct scsi_target *starget = NULL;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+ u16 volume_handle = 0;
+ u64 volume_wwid = 0;
+
+ mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
+ if (volume_handle)
+ mpt2sas_config_get_volume_wwid(ioc, volume_handle,
+ &volume_wwid);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device) {
+ set_bit(handle, ioc->pd_handles);
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->flags |=
+ MPT_TARGET_FLAGS_RAID_COMPONENT;
+ sas_device->volume_handle = volume_handle;
+ sas_device->volume_wwid = volume_wwid;
+ }
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
/* hiding raid component */
- mpt2sas_config_get_volume_handle(ioc, handle,
- &sas_device->volume_handle);
- mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
- &sas_device->volume_wwid);
- set_bit(handle, ioc->pd_handles);
- _scsih_reprobe_target(sas_device->starget, 1);
-
+ if (starget)
+ starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
}
/**
@@ -6132,16 +6186,9 @@ static void
_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
- struct _sas_device *sas_device;
- unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
- _scsih_remove_device(ioc, sas_device);
+ _scsih_device_remove_by_handle(ioc, handle);
}
/**
@@ -6583,18 +6630,13 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
/* code added for raid transport support */
if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
- handle = le16_to_cpu(event_data->VolDevHandle);
-
spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ handle = le16_to_cpu(event_data->VolDevHandle);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!raid_device)
- return;
-
- if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
+ if (raid_device)
raid_device->percent_complete =
event_data->PercentComplete;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
}
@@ -6761,13 +6803,18 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
* required data for Direct IO
*/
_scsih_init_warpdrive_properties(ioc, raid_device);
- if (raid_device->handle == handle)
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ if (raid_device->handle == handle) {
+ spin_unlock_irqrestore(&ioc->raid_device_lock,
+ flags);
return;
+ }
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
raid_device->handle);
raid_device->handle = handle;
if (sas_target_priv_data)
sas_target_priv_data->handle = handle;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
return;
}
}
@@ -6939,58 +6986,56 @@ static void
_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
{
struct _sas_device *sas_device, *sas_device_next;
- struct _sas_node *sas_expander;
+ struct _sas_node *sas_expander, *sas_expander_next;
struct _raid_device *raid_device, *raid_device_next;
+ struct list_head tmp_list;
+ unsigned long flags;
printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
ioc->name);
+ /* removing unresponding end devices */
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
+ ioc->name);
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
- if (sas_device->responding) {
+ if (!sas_device->responding)
+ mpt2sas_device_remove_by_sas_address(ioc,
+ sas_device->sas_address);
+ else
sas_device->responding = 0;
- continue;
- }
- if (sas_device->starget)
- starget_printk(KERN_INFO, sas_device->starget,
- "removing: handle(0x%04x), sas_addr(0x%016llx), "
- "enclosure logical id(0x%016llx), slot(%d)\n",
- sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
- _scsih_remove_device(ioc, sas_device);
}
- if (!ioc->ir_firmware)
- goto retry_expander_search;
-
- list_for_each_entry_safe(raid_device, raid_device_next,
- &ioc->raid_device_list, list) {
- if (raid_device->responding) {
- raid_device->responding = 0;
- continue;
- }
- if (raid_device->starget) {
- starget_printk(KERN_INFO, raid_device->starget,
- "removing: handle(0x%04x), wwid(0x%016llx)\n",
- raid_device->handle,
- (unsigned long long)raid_device->wwid);
- scsi_remove_target(&raid_device->starget->dev);
+ /* removing unresponding volumes */
+ if (ioc->ir_firmware) {
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
+ "volumes\n", ioc->name);
+ list_for_each_entry_safe(raid_device, raid_device_next,
+ &ioc->raid_device_list, list) {
+ if (!raid_device->responding)
+ _scsih_sas_volume_delete(ioc,
+ raid_device->handle);
+ else
+ raid_device->responding = 0;
}
- _scsih_raid_device_remove(ioc, raid_device);
}
-
- retry_expander_search:
- sas_expander = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->responding) {
+ /* removing unresponding expanders */
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
+ ioc->name);
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ INIT_LIST_HEAD(&tmp_list);
+ list_for_each_entry_safe(sas_expander, sas_expander_next,
+ &ioc->sas_expander_list, list) {
+ if (!sas_expander->responding)
+ list_move_tail(&sas_expander->list, &tmp_list);
+ else
sas_expander->responding = 0;
- continue;
- }
- mpt2sas_expander_remove(ioc, sas_expander->sas_address);
- goto retry_expander_search;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
+ list) {
+ list_del(&sas_expander->list);
+ _scsih_expander_node_remove(ioc, sas_expander);
}
printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
ioc->name);
@@ -7043,6 +7088,7 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
struct _sas_device *sas_device;
struct _sas_node *expander_device;
static struct _raid_device *raid_device;
+ unsigned long flags;
printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
@@ -7057,8 +7103,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(expander_pg0.DevHandle);
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_device = mpt2sas_scsih_expander_find_by_sas_address(
ioc, le64_to_cpu(expander_pg0.SASAddress));
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (expander_device)
_scsih_refresh_expander_links(ioc, expander_device,
handle);
@@ -7080,7 +7128,9 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
break;
phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle);
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device)
continue;
if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
@@ -7107,8 +7157,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(volume_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_wwid(ioc,
le64_to_cpu(volume_pg1.WWID));
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (raid_device)
continue;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
@@ -7140,8 +7192,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (!(_scsih_is_end_device(
le32_to_cpu(sas_device_pg0.DeviceInfo))))
continue;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
le64_to_cpu(sas_device_pg0.SASAddress));
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device)
continue;
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
@@ -7235,7 +7289,7 @@ _firmware_event_work(struct work_struct *work)
switch (fw_event->event) {
case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost))
+ while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
ssleep(1);
_scsih_remove_unresponding_sas_devices(ioc);
_scsih_scan_for_devices_after_reset(ioc);
@@ -7313,6 +7367,13 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
return 1;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
+
event = le16_to_cpu(mpi_reply->Event);
switch (event) {
@@ -7353,14 +7414,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_LOG_ENTRY_ADDED:
{
Mpi2EventDataLogEntryAdded_t *log_entry;
- u32 *log_code;
+ __le32 *log_code;
if (!ioc->is_warpdrive)
break;
log_entry = (Mpi2EventDataLogEntryAdded_t *)
mpi_reply->EventData;
- log_code = (u32 *)log_entry->LogData;
+ log_code = (__le32 *)log_entry->LogData;
if (le16_to_cpu(log_entry->LogEntryQualifier)
!= MPT2_WARPDRIVE_LOGENTRY)
@@ -7487,7 +7548,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
return;
if (mpt2sas_port->remote_identify.device_type ==
SAS_END_DEVICE)
- mpt2sas_device_remove(ioc,
+ mpt2sas_device_remove_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
else if (mpt2sas_port->remote_identify.device_type ==
SAS_EDGE_EXPANDER_DEVICE ||
@@ -7661,7 +7722,7 @@ _scsih_remove(struct pci_dev *pdev)
&ioc->sas_hba.sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
SAS_END_DEVICE)
- mpt2sas_device_remove(ioc,
+ mpt2sas_device_remove_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
else if (mpt2sas_port->remote_identify.device_type ==
SAS_EDGE_EXPANDER_DEVICE ||
@@ -7733,11 +7794,11 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
} else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = device;
handle = sas_device->handle;
sas_address_parent = sas_device->sas_address_parent;
sas_address = sas_device->sas_address;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -8061,8 +8122,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_thread_fail:
list_del(&ioc->list);
scsi_remove_host(shost);
- scsi_host_put(shost);
out_add_shost_fail:
+ scsi_host_put(shost);
return -ENODEV;
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 831047466a5..c6cf20f6072 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -163,12 +163,15 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
return -EIO;
}
- memset(identify, 0, sizeof(*identify));
+ memset(identify, 0, sizeof(struct sas_identify));
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
/* sas_address */
identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+ /* phy number of the parent device this device is linked to */
+ identify->phy_identifier = sas_device_pg0.PhyNum;
+
/* device_type */
switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
@@ -484,7 +487,7 @@ _transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
ioc->logging_level |= MPT_DEBUG_TRANSPORT;
if (device_type == SAS_END_DEVICE)
- mpt2sas_device_remove(ioc, sas_address);
+ mpt2sas_device_remove_by_sas_address(ioc, sas_address);
else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
device_type == SAS_FANOUT_EXPANDER_DEVICE)
mpt2sas_expander_remove(ioc, sas_address);
@@ -792,9 +795,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_sas_address(ioc,
sas_address_parent);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_node)
+ if (!sas_node) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
port_list) {
if (mpt2sas_port->remote_identify.sas_address != sas_address)
@@ -804,8 +808,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
goto out;
}
out:
- if (!found)
+ if (!found) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
for (i = 0; i < sas_node->num_phys; i++) {
if (sas_node->phy[i].remote_identify.sas_address == sas_address)
@@ -813,6 +819,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
sizeof(struct sas_identify));
}
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
list_for_each_entry_safe(mpt2sas_phy, next_phy,
&mpt2sas_port->phy_list, port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
@@ -986,12 +993,14 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_node)
+ if (!sas_node) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
mpt2sas_phy = &sas_node->phy[phy_number];
mpt2sas_phy->attached_handle = handle;
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
_transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
@@ -1310,17 +1319,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_device *sas_device;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
+ if (sas_device) {
+ *identifier = sas_device->enclosure_logical_id;
+ rc = 0;
+ } else {
+ *identifier = 0;
+ rc = -ENXIO;
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!sas_device)
- return -ENXIO;
-
- *identifier = sas_device->enclosure_logical_id;
- return 0;
+ return rc;
}
/**
@@ -1335,16 +1347,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_device *sas_device;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
+ if (sas_device)
+ rc = sas_device->slot;
+ else
+ rc = -ENXIO;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!sas_device)
- return -ENXIO;
-
- return sas_device->slot;
+ return rc;
}
/* phy control request structure */
@@ -1629,11 +1642,13 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
u16 sz;
int rc = 0;
unsigned long flags;
+ int i, discovery_active;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
if (_transport_sas_node_find_by_sas_address(ioc,
@@ -1651,7 +1666,50 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
/* handle hba phys */
- /* sas_iounit page 1 */
+ /* read sas_iounit page 0 */
+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
+ sizeof(Mpi2SasIOUnit0PhyData_t));
+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg0) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+ sas_iounit_pg0, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENXIO;
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -EIO;
+ goto out;
+ }
+
+ /* unable to enable/disable phys when when discovery is active */
+ for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {
+ if (sas_iounit_pg0->PhyData[i].PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
+ printk(MPT2SAS_ERR_FMT "discovery is active on "
+ "port = %d, phy = %d: unable to enable/disable "
+ "phys, try again later!\n", ioc->name,
+ sas_iounit_pg0->PhyData[i].Port, i);
+ discovery_active = 1;
+ }
+ }
+
+ if (discovery_active) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ /* read sas_iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
@@ -1676,7 +1734,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
rc = -EIO;
goto out;
}
-
+ /* copy Port/PortFlags/PhyFlags from page 0 */
+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ sas_iounit_pg1->PhyData[i].Port =
+ sas_iounit_pg0->PhyData[i].Port;
+ sas_iounit_pg1->PhyData[i].PortFlags =
+ (sas_iounit_pg0->PhyData[i].PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);
+ sas_iounit_pg1->PhyData[i].PhyFlags =
+ (sas_iounit_pg0->PhyData[i].PhyFlags &
+ (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +
+ MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));
+ }
if (enable)
sas_iounit_pg1->PhyData[phy->number].PhyFlags
&= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
@@ -1692,6 +1761,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
out:
kfree(sas_iounit_pg1);
+ kfree(sas_iounit_pg0);
return rc;
}
@@ -1828,7 +1898,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Mpi2SmpPassthroughRequest_t *mpi_request;
Mpi2SmpPassthroughReply_t *mpi_reply;
- int rc;
+ int rc, i;
u16 smid;
u32 ioc_state;
unsigned long timeleft;
@@ -1837,24 +1907,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u8 issue_reset = 0;
dma_addr_t dma_addr_in = 0;
dma_addr_t dma_addr_out = 0;
+ dma_addr_t pci_dma_in = 0;
+ dma_addr_t pci_dma_out = 0;
+ void *pci_addr_in = NULL;
+ void *pci_addr_out = NULL;
u16 wait_state_count;
struct request *rsp = req->next_rq;
+ struct bio_vec *bvec = NULL;
if (!rsp) {
printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
"missing\n", ioc->name, __func__);
return -EINVAL;
}
-
- /* do we need to support multiple segments? */
- if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
- printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
- "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
- blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
- return -EINVAL;
- }
-
- if (ioc->shost_recovery) {
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
@@ -1872,6 +1938,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
}
ioc->transport_cmds.status = MPT2_CMD_PENDING;
+ /* Check if the request is split across multiple segments */
+ if (req->bio->bi_vcnt > 1) {
+ u32 offset = 0;
+
+ /* Allocate memory and copy the request */
+ pci_addr_out = pci_alloc_consistent(ioc->pdev,
+ blk_rq_bytes(req), &pci_dma_out);
+ if (!pci_addr_out) {
+ printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ bio_for_each_segment(bvec, req->bio, i) {
+ memcpy(pci_addr_out + offset,
+ page_address(bvec->bv_page) + bvec->bv_offset,
+ bvec->bv_len);
+ offset += bvec->bv_len;
+ }
+ } else {
+ dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
+ blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_out) {
+ printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto free_pci;
+ }
+ }
+
+ /* Check if the response needs to be populated across
+ * multiple segments */
+ if (rsp->bio->bi_vcnt > 1) {
+ pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
+ &pci_dma_in);
+ if (!pci_addr_in) {
+ printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto unmap;
+ }
+ } else {
+ dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
+ blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_in) {
+ printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto unmap;
+ }
+ }
+
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
@@ -1880,7 +1999,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
rc = -EFAULT;
- goto out;
+ goto unmap;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
@@ -1897,7 +2016,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
- goto out;
+ goto unmap;
}
rc = 0;
@@ -1919,16 +2038,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
- blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_out) {
- mpt2sas_base_free_smid(ioc, smid);
- goto unmap;
+ if (req->bio->bi_vcnt > 1) {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(req) - 4), pci_dma_out);
+ } else {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(req) - 4), dma_addr_out);
}
- ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
- dma_addr_out);
-
/* incr sgel */
psge += ioc->sge_size;
@@ -1937,16 +2054,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
MPI2_SGE_FLAGS_END_OF_LIST);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
- blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_in) {
- mpt2sas_base_free_smid(ioc, smid);
- goto unmap;
+ if (rsp->bio->bi_vcnt > 1) {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(rsp) + 4), pci_dma_in);
+ } else {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(rsp) + 4), dma_addr_in);
}
- ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
- dma_addr_in);
-
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
@@ -1982,6 +2097,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
req->resid_len = 0;
rsp->resid_len -=
le16_to_cpu(mpi_reply->ResponseDataLength);
+ /* check if the resp needs to be copied from the allocated
+ * pci mem */
+ if (rsp->bio->bi_vcnt > 1) {
+ u32 offset = 0;
+ u32 bytes_to_copy =
+ le16_to_cpu(mpi_reply->ResponseDataLength);
+ bio_for_each_segment(bvec, rsp->bio, i) {
+ if (bytes_to_copy <= bvec->bv_len) {
+ memcpy(page_address(bvec->bv_page) +
+ bvec->bv_offset, pci_addr_in +
+ offset, bytes_to_copy);
+ break;
+ } else {
+ memcpy(page_address(bvec->bv_page) +
+ bvec->bv_offset, pci_addr_in +
+ offset, bvec->bv_len);
+ bytes_to_copy -= bvec->bv_len;
+ }
+ offset += bvec->bv_len;
+ }
+ }
} else {
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - no reply\n", ioc->name, __func__));
@@ -2003,6 +2139,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
PCI_DMA_BIDIRECTIONAL);
+ free_pci:
+ if (pci_addr_out)
+ pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
+ pci_dma_out);
+
+ if (pci_addr_in)
+ pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
+ pci_dma_in);
+
out:
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->transport_cmds.mutex);
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index 944afada61e..c3d20c8d4ab 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -66,9 +66,10 @@ enum port_type {
/* driver compile-time configuration */
#define PM8001_MAX_CCB 512 /* max ccbs supported */
+#define PM8001_MPI_QUEUE 1024 /* maximum mpi queue entries */
#define PM8001_MAX_INB_NUM 1
#define PM8001_MAX_OUTB_NUM 1
-#define PM8001_CAN_QUEUE 128 /* SCSI Queue depth */
+#define PM8001_CAN_QUEUE 508 /* SCSI Queue depth */
/* unchangeable hardware details */
#define PM8001_MAX_PHYS 8 /* max. possible phys */
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 9d82ee5c10d..bf54aafc2d7 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -192,7 +192,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl.fatal_err_interrupt = 0x01;
for (i = 0; i < qn; i++) {
pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
- 0x00000100 | (0x00000040 << 16) | (0x00<<30);
+ PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[IB].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
@@ -218,7 +218,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha)
}
for (i = 0; i < qn; i++) {
pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
- 256 | (64 << 16) | (1<<30);
+ PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[OB].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
@@ -1245,7 +1245,7 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
/* Stores the new consumer index */
consumer_index = pm8001_read_32(circularQ->ci_virt);
circularQ->consumer_index = cpu_to_le32(consumer_index);
- if (((circularQ->producer_idx + bcCount) % 256) ==
+ if (((circularQ->producer_idx + bcCount) % PM8001_MPI_QUEUE) ==
le32_to_cpu(circularQ->consumer_index)) {
*messagePtr = NULL;
return -1;
@@ -1253,7 +1253,8 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
/* get memory IOMB buffer address */
offset = circularQ->producer_idx * 64;
/* increment to next bcCount element */
- circularQ->producer_idx = (circularQ->producer_idx + bcCount) % 256;
+ circularQ->producer_idx = (circularQ->producer_idx + bcCount)
+ % PM8001_MPI_QUEUE;
/* Adds that distance to the base of the region virtual address plus
the message header size*/
msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + offset);
@@ -1326,7 +1327,8 @@ static u32 mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
return 0;
}
/* free the circular queue buffer elements associated with the message*/
- circularQ->consumer_idx = (circularQ->consumer_idx + bc) % 256;
+ circularQ->consumer_idx = (circularQ->consumer_idx + bc)
+ % PM8001_MPI_QUEUE;
/* update the CI of outbound queue */
pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset,
circularQ->consumer_idx);
@@ -1383,7 +1385,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
circularQ->consumer_idx =
(circularQ->consumer_idx +
((le32_to_cpu(msgHeader_tmp)
- >> 24) & 0x1f)) % 256;
+ >> 24) & 0x1f))
+ % PM8001_MPI_QUEUE;
msgHeader_tmp = 0;
pm8001_write_32(msgHeader, 0, 0);
/* update the CI of outbound queue */
@@ -1396,7 +1399,7 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
circularQ->consumer_idx =
(circularQ->consumer_idx +
((le32_to_cpu(msgHeader_tmp) >> 24) &
- 0x1f)) % 256;
+ 0x1f)) % PM8001_MPI_QUEUE;
msgHeader_tmp = 0;
pm8001_write_32(msgHeader, 0, 0);
/* update the CI of outbound queue */
@@ -3357,7 +3360,7 @@ mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
struct fw_control_ex fw_control_context;
struct fw_flash_Update_resp *ppayload =
(struct fw_flash_Update_resp *)(piomb + 4);
- u32 tag = ppayload->tag;
+ u32 tag = le32_to_cpu(ppayload->tag);
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
status = le32_to_cpu(ppayload->status);
memcpy(&fw_control_context,
@@ -3703,8 +3706,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
*/
static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
- u32 pHeader = (u32)*(u32 *)piomb;
- u8 opc = (u8)(pHeader & 0xFFF);
+ __le32 pHeader = *(__le32 *)piomb;
+ u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 1a4611eb032..d437309cb1e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -599,7 +599,7 @@ struct fw_flash_Update_req {
*
*/
struct fw_flash_Update_resp {
- dma_addr_t tag;
+ __le32 tag;
__le32 status;
u32 reserved[13];
} __attribute__((packed, aligned(4)));
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 36efaa7c3a5..0267c22f874 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -235,15 +235,15 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->memoryMap.region[PI].alignment = 4;
/* MPI Memory region 5 inbound queues */
- pm8001_ha->memoryMap.region[IB].num_elements = 256;
+ pm8001_ha->memoryMap.region[IB].num_elements = PM8001_MPI_QUEUE;
pm8001_ha->memoryMap.region[IB].element_size = 64;
- pm8001_ha->memoryMap.region[IB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[IB].total_len = PM8001_MPI_QUEUE * 64;
pm8001_ha->memoryMap.region[IB].alignment = 64;
- /* MPI Memory region 6 inbound queues */
- pm8001_ha->memoryMap.region[OB].num_elements = 256;
+ /* MPI Memory region 6 outbound queues */
+ pm8001_ha->memoryMap.region[OB].num_elements = PM8001_MPI_QUEUE;
pm8001_ha->memoryMap.region[OB].element_size = 64;
- pm8001_ha->memoryMap.region[OB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[OB].total_len = PM8001_MPI_QUEUE * 64;
pm8001_ha->memoryMap.region[OB].alignment = 64;
/* Memory region write DMA*/
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 07322ecff90..61c82a345f8 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -90,6 +90,12 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_BLK_DEV_SD)
+/* sd and scsi_pm need to coordinate flushing async actions */
+LIST_HEAD(scsi_sd_probe_domain);
+EXPORT_SYMBOL(scsi_sd_probe_domain);
+#endif
+
/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
* You may not alter any existing entry (although adding new ones is
* encouraged once assigned by ANSI/INCITS T10
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5dfd7495d1a..62ddfd31d4c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2348,10 +2348,14 @@ EXPORT_SYMBOL(scsi_device_quiesce);
*
* Must be called with user context, may sleep.
*/
-void
-scsi_device_resume(struct scsi_device *sdev)
+void scsi_device_resume(struct scsi_device *sdev)
{
- if(scsi_device_set_state(sdev, SDEV_RUNNING))
+ /* check if the device state was mutated prior to resume, and if
+ * so assume the state is being managed elsewhere (for example
+ * device deleted during suspend)
+ */
+ if (sdev->sdev_state != SDEV_QUIESCE ||
+ scsi_device_set_state(sdev, SDEV_RUNNING))
return;
scsi_run_queue(sdev->request_queue);
}
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index c4670642d02..f661a41fa4c 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -97,7 +97,7 @@ static int scsi_bus_prepare(struct device *dev)
{
if (scsi_is_sdev_device(dev)) {
/* sd probing uses async_schedule. Wait until it finishes. */
- async_synchronize_full();
+ async_synchronize_full_domain(&scsi_sd_probe_domain);
} else if (scsi_is_host_device(dev)) {
/* Wait until async scanning is finished */
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index be4fa6d179b..07ce3f51701 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -163,6 +163,8 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM_RUNTIME */
+extern struct list_head scsi_sd_probe_domain;
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 80fbe2ac0b4..579760420d5 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2808,17 +2808,20 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
FC_RPORT_DEVLOSS_PENDING |
FC_RPORT_DEVLOSS_CALLBK_DONE);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
/* if target, initiate a scan */
if (rport->scsi_target_id != -1) {
+ scsi_target_unblock(&rport->dev);
+
+ spin_lock_irqsave(shost->host_lock,
+ flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost,
&rport->scan_work);
spin_unlock_irqrestore(shost->host_lock,
flags);
- scsi_target_unblock(&rport->dev);
- } else
- spin_unlock_irqrestore(shost->host_lock,
- flags);
+ }
fc_bsg_goose_queue(rport);
@@ -2876,16 +2879,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
if (fci->f->dd_fcrport_size)
memset(rport->dd_data, 0,
fci->f->dd_fcrport_size);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (ids->roles & FC_PORT_ROLE_FCP_TARGET) {
+ scsi_target_unblock(&rport->dev);
- if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
+ spin_lock_irqsave(shost->host_lock, flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_target_unblock(&rport->dev);
- } else
- spin_unlock_irqrestore(shost->host_lock, flags);
-
+ }
return rport;
}
}
@@ -3083,12 +3087,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
/* ensure any stgt delete functions are done */
fc_flush_work(shost);
+ scsi_target_unblock(&rport->dev);
/* initiate a scan of the target */
spin_lock_irqsave(shost->host_lock, flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_target_unblock(&rport->dev);
}
}
EXPORT_SYMBOL(fc_remote_port_rolechg);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index a2715c31e75..cf08071a9b6 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -1010,10 +1010,10 @@ spi_dv_device(struct scsi_device *sdev)
u8 *buffer;
const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
- if (unlikely(scsi_device_get(sdev)))
+ if (unlikely(spi_dv_in_progress(starget)))
return;
- if (unlikely(spi_dv_in_progress(starget)))
+ if (unlikely(scsi_device_get(sdev)))
return;
spi_dv_in_progress(starget) = 1;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5ba5c2a9e8e..6f0a4c612b3 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -65,6 +65,7 @@
#include <scsi/scsicam.h>
#include "sd.h"
+#include "scsi_priv.h"
#include "scsi_logging.h"
MODULE_AUTHOR("Eric Youngdale");
@@ -2722,7 +2723,7 @@ static int sd_probe(struct device *dev)
dev_set_drvdata(dev, sdkp);
get_device(&sdkp->dev); /* prevent release before async_schedule */
- async_schedule(sd_probe_async, sdkp);
+ async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
return 0;
@@ -2756,7 +2757,7 @@ static int sd_remove(struct device *dev)
sdkp = dev_get_drvdata(dev);
scsi_autopm_get_device(sdkp->device);
- async_synchronize_full();
+ async_synchronize_full_domain(&scsi_sd_probe_domain);
blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
blk_queue_unprep_rq(sdkp->device->request_queue, NULL);
device_del(&sdkp->dev);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index eacd46bb36b..9c5c5f2b396 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -104,7 +104,7 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
static int sg_add(struct device *, struct class_interface *);
static void sg_remove(struct device *, struct class_interface *);
-static DEFINE_MUTEX(sg_mutex);
+static DEFINE_SPINLOCK(sg_open_exclusive_lock);
static DEFINE_IDR(sg_index_idr);
static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
@@ -137,13 +137,15 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
char orphan; /* 1 -> drop on sight, 0 -> normal */
char sg_io_owned; /* 1 -> packet belongs to SG_IO */
- volatile char done; /* 0->before bh, 1->before read, 2->read */
+ /* done protected by rq_list_lock */
+ char done; /* 0->before bh, 1->before read, 2->read */
struct request *rq;
struct bio *bio;
struct execute_work ew;
} Sg_request;
typedef struct sg_fd { /* holds the state of a file descriptor */
+ /* sfd_siblings is protected by sg_index_lock */
struct list_head sfd_siblings;
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
@@ -157,7 +159,6 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
char low_dma; /* as in parent but possibly overridden to 1 */
char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
- volatile char closed; /* 1 -> fd closed but request(s) outstanding */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
@@ -171,9 +172,11 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
u32 index; /* device index number */
+ /* sfds is protected by sg_index_lock */
struct list_head sfds;
volatile char detached; /* 0->attached, 1->detached pending removal */
- volatile char exclude; /* opened for exclusive access */
+ /* exclude protected by sg_open_exclusive_lock */
+ char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
struct gendisk *disk;
struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */
@@ -221,6 +224,38 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd)
return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
}
+static int get_exclude(Sg_device *sdp)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+ ret = sdp->exclude;
+ spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+ return ret;
+}
+
+static int set_exclude(Sg_device *sdp, char val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+ sdp->exclude = val;
+ spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+ return val;
+}
+
+static int sfds_list_empty(Sg_device *sdp)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&sg_index_lock, flags);
+ ret = list_empty(&sdp->sfds);
+ read_unlock_irqrestore(&sg_index_lock, flags);
+ return ret;
+}
+
static int
sg_open(struct inode *inode, struct file *filp)
{
@@ -232,7 +267,6 @@ sg_open(struct inode *inode, struct file *filp)
int res;
int retval;
- mutex_lock(&sg_mutex);
nonseekable_open(inode, filp);
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
sdp = sg_get_dev(dev);
@@ -264,25 +298,22 @@ sg_open(struct inode *inode, struct file *filp)
retval = -EPERM; /* Can't lock it with read only access */
goto error_out;
}
- if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) {
+ if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
retval = -EBUSY;
goto error_out;
}
- res = 0;
- __wait_event_interruptible(sdp->o_excl_wait,
- ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
+ res = wait_event_interruptible(sdp->o_excl_wait,
+ ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
if (res) {
retval = res; /* -ERESTARTSYS because signal hit process */
goto error_out;
}
- } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
+ } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
if (flags & O_NONBLOCK) {
retval = -EBUSY;
goto error_out;
}
- res = 0;
- __wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude),
- res);
+ res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
if (res) {
retval = res; /* -ERESTARTSYS because signal hit process */
goto error_out;
@@ -292,7 +323,7 @@ sg_open(struct inode *inode, struct file *filp)
retval = -ENODEV;
goto error_out;
}
- if (list_empty(&sdp->sfds)) { /* no existing opens on this device */
+ if (sfds_list_empty(sdp)) { /* no existing opens on this device */
sdp->sgdebug = 0;
q = sdp->device->request_queue;
sdp->sg_tablesize = queue_max_segments(q);
@@ -301,7 +332,7 @@ sg_open(struct inode *inode, struct file *filp)
filp->private_data = sfp;
else {
if (flags & O_EXCL) {
- sdp->exclude = 0; /* undo if error */
+ set_exclude(sdp, 0); /* undo if error */
wake_up_interruptible(&sdp->o_excl_wait);
}
retval = -ENOMEM;
@@ -317,7 +348,6 @@ sdp_put:
sg_put:
if (sdp)
sg_put_dev(sdp);
- mutex_unlock(&sg_mutex);
return retval;
}
@@ -332,9 +362,7 @@ sg_release(struct inode *inode, struct file *filp)
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
- sfp->closed = 1;
-
- sdp->exclude = 0;
+ set_exclude(sdp, 0);
wake_up_interruptible(&sdp->o_excl_wait);
scsi_autopm_put_device(sdp->device);
@@ -398,19 +426,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
retval = -EAGAIN;
goto free_old_hdr;
}
- while (1) {
- retval = 0; /* following macro beats race condition */
- __wait_event_interruptible(sfp->read_wait,
- (sdp->detached ||
- (srp = sg_get_rq_mark(sfp, req_pack_id))),
- retval);
- if (sdp->detached) {
- retval = -ENODEV;
- goto free_old_hdr;
- }
- if (0 == retval)
- break;
-
+ retval = wait_event_interruptible(sfp->read_wait,
+ (sdp->detached ||
+ (srp = sg_get_rq_mark(sfp, req_pack_id))));
+ if (sdp->detached) {
+ retval = -ENODEV;
+ goto free_old_hdr;
+ }
+ if (retval) {
/* -ERESTARTSYS as signal hit process */
goto free_old_hdr;
}
@@ -771,7 +794,18 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return 0;
}
-static int
+static int srp_done(Sg_fd *sfp, Sg_request *srp)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&sfp->rq_list_lock, flags);
+ ret = srp->done;
+ read_unlock_irqrestore(&sfp->rq_list_lock, flags);
+ return ret;
+}
+
+static long
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
void __user *p = (void __user *)arg;
@@ -791,40 +825,30 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
switch (cmd_in) {
case SG_IO:
- {
- int blocking = 1; /* ignore O_NONBLOCK flag */
-
- if (sdp->detached)
- return -ENODEV;
- if (!scsi_block_when_processing_errors(sdp->device))
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
- return -EFAULT;
- result =
- sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
- blocking, read_only, 1, &srp);
- if (result < 0)
- return result;
- while (1) {
- result = 0; /* following macro to beat race condition */
- __wait_event_interruptible(sfp->read_wait,
- (srp->done || sdp->detached),
- result);
- if (sdp->detached)
- return -ENODEV;
- write_lock_irq(&sfp->rq_list_lock);
- if (srp->done) {
- srp->done = 2;
- write_unlock_irq(&sfp->rq_list_lock);
- break;
- }
- srp->orphan = 1;
- write_unlock_irq(&sfp->rq_list_lock);
- return result; /* -ERESTARTSYS because signal hit process */
- }
+ if (sdp->detached)
+ return -ENODEV;
+ if (!scsi_block_when_processing_errors(sdp->device))
+ return -ENXIO;
+ if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
+ return -EFAULT;
+ result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
+ 1, read_only, 1, &srp);
+ if (result < 0)
+ return result;
+ result = wait_event_interruptible(sfp->read_wait,
+ (srp_done(sfp, srp) || sdp->detached));
+ if (sdp->detached)
+ return -ENODEV;
+ write_lock_irq(&sfp->rq_list_lock);
+ if (srp->done) {
+ srp->done = 2;
+ write_unlock_irq(&sfp->rq_list_lock);
result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
return (result < 0) ? result : 0;
}
+ srp->orphan = 1;
+ write_unlock_irq(&sfp->rq_list_lock);
+ return result; /* -ERESTARTSYS because signal hit process */
case SG_SET_TIMEOUT:
result = get_user(val, ip);
if (result)
@@ -1091,18 +1115,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
}
}
-static long
-sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&sg_mutex);
- ret = sg_ioctl(filp, cmd_in, arg);
- mutex_unlock(&sg_mutex);
-
- return ret;
-}
-
#ifdef CONFIG_COMPAT
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
@@ -1136,8 +1148,11 @@ sg_poll(struct file *filp, poll_table * wait)
int count = 0;
unsigned long iflags;
- if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))
- || sfp->closed)
+ sfp = filp->private_data;
+ if (!sfp)
+ return POLLERR;
+ sdp = sfp->parentdp;
+ if (!sdp)
return POLLERR;
poll_wait(filp, &sfp->read_wait, wait);
read_lock_irqsave(&sfp->rq_list_lock, iflags);
@@ -1347,7 +1362,7 @@ static const struct file_operations sg_fops = {
.read = sg_read,
.write = sg_write,
.poll = sg_poll,
- .unlocked_ioctl = sg_unlocked_ioctl,
+ .unlocked_ioctl = sg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = sg_compat_ioctl,
#endif
@@ -2312,7 +2327,7 @@ struct sg_proc_leaf {
const struct file_operations * fops;
};
-static struct sg_proc_leaf sg_proc_leaf_arr[] = {
+static const struct sg_proc_leaf sg_proc_leaf_arr[] = {
{"allow_dio", &adio_fops},
{"debug", &debug_fops},
{"def_reserved_size", &dressz_fops},
@@ -2332,7 +2347,7 @@ sg_proc_init(void)
if (!sg_proc_sgp)
return 1;
for (k = 0; k < num_leaves; ++k) {
- struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k];
+ const struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k];
umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops);
}
@@ -2533,9 +2548,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
fp->reserve.bufflen,
(int) fp->reserve.k_use_sg,
(int) fp->low_dma);
- seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
+ seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
(int) fp->cmd_q, (int) fp->force_packid,
- (int) fp->keep_orphan, (int) fp->closed);
+ (int) fp->keep_orphan);
for (m = 0, srp = fp->headrp;
srp != NULL;
++m, srp = srp->nextrp) {
@@ -2612,7 +2627,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
scsidp->lun,
scsidp->host->hostt->emulated);
seq_printf(s, " sg_tablesize=%d excl=%d\n",
- sdp->sg_tablesize, sdp->exclude);
+ sdp->sg_tablesize, get_exclude(sdp));
sg_proc_debug_helper(s, sdp);
}
read_unlock_irqrestore(&sg_index_lock, iflags);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index ea35632b986..b548923785e 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -35,8 +35,8 @@ struct st_request {
/* The tape buffer descriptor. */
struct st_buffer {
unsigned char dma; /* DMA-able buffer */
- unsigned char do_dio; /* direct i/o set up? */
unsigned char cleared; /* internal buffer cleared after open? */
+ unsigned short do_dio; /* direct i/o set up? */
int buffer_size;
int buffer_blocks;
int buffer_bytes;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 83a1972a199..528d52beaa1 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -785,12 +785,22 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
/*
* If there is an error; offline the device since all
* error recovery strategies would have already been
- * deployed on the host side.
+ * deployed on the host side. However, if the command
+ * were a pass-through command deal with it appropriately.
*/
- if (vm_srb->srb_status == SRB_STATUS_ERROR)
- scmnd->result = DID_TARGET_FAILURE << 16;
- else
- scmnd->result = vm_srb->scsi_status;
+ scmnd->result = vm_srb->scsi_status;
+
+ if (vm_srb->srb_status == SRB_STATUS_ERROR) {
+ switch (scmnd->cmnd[0]) {
+ case ATA_16:
+ case ATA_12:
+ set_host_byte(scmnd, DID_PASSTHROUGH);
+ break;
+ default:
+ set_host_byte(scmnd, DID_TARGET_FAILURE);
+ }
+ }
+
/*
* If the LUN is invalid; remove the device.
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 52b96e8bf92..4e010b72781 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1032,11 +1032,11 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
return -EIO;
/* Configure UTRL and UTMRL base address registers */
- writel(hba->utrdl_dma_addr,
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
writel(lower_32_bits(hba->utrdl_dma_addr),
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
+ writel(upper_32_bits(hba->utrdl_dma_addr),
(hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
- writel(hba->utmrdl_dma_addr,
+ writel(lower_32_bits(hba->utmrdl_dma_addr),
(hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
writel(upper_32_bits(hba->utmrdl_dma_addr),
(hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
@@ -1160,7 +1160,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
task_result = be32_to_cpu(task_rsp_upiup->header.dword_1);
task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
- if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL ||
+ if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL &&
task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
task_result = FAILED;
} else {
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 988ba06b3ad..c1260d80ef3 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -661,6 +661,8 @@ struct iscsi_reject {
#define ISCSI_DEF_TIME2WAIT 2
+#define ISCSI_NAME_LEN 224
+
/************************* RFC 3720 End *****************************/
#endif /* ISCSI_PROTO_H */