From cc4959c11abc9a41860b0eac11921fcd19b1a1ca Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:25 +0100 Subject: [PATCH 001/101] ufs: fixed typo in ufshcd-pltfrm Fixed typo in ufshcd-pltfrm. Signed-off-by: Joao Pinto Acked-by: Arnd Bergmann Acked-by: Tomas Winkler Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd-pltfrm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 718f12e09885..db53f38da864 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -372,6 +372,6 @@ EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); MODULE_AUTHOR("Santosh Yaragnavi "); MODULE_AUTHOR("Vinayak Holikatti "); -MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver"); +MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(UFSHCD_DRIVER_VERSION); From b1d78f27255203f74fcfa0a8329c1b73015de132 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:26 +0100 Subject: [PATCH 002/101] ufs: add UFS 2.0 to ufshcd-pltfrm bindings Add UFS 2.0 to the ufshcd-pltfrm devicetree binding. Signed-off-by: Joao Pinto Acked-by: Rob Herring Acked-by: Tomas Winkler Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index 66f6adf8d44d..a99ed5565b26 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -4,8 +4,8 @@ UFSHC nodes are defined to describe on-chip UFS host controllers. Each UFS controller instance should have its own node. Required properties: -- compatible : must contain "jedec,ufs-1.1", may also list one or more - of the following: +- compatible : must contain "jedec,ufs-1.1" or "jedec,ufs-2.0", may + also list one or more of the following: "qcom,msm8994-ufshc" "qcom,msm8996-ufshc" "qcom,ufshc" From 300bb13f5c7b1d6b970d32232d0462ae36d50b9d Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:27 +0100 Subject: [PATCH 003/101] ufs: add UFS 2.0 capabilities Add UFS 2.0 support to the UFS core driver. Signed-off-by: Joao Pinto Acked-by: Arnd Bergmann Acked-by: Tomas Winkler Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 89 +++++++++++++++++++++------------------ drivers/scsi/ufs/ufshci.h | 5 +++ 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index f8fa72c31a9d..8e8989a1859b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1173,7 +1173,7 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) * @cmd_dir: requests data direction */ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, - u32 *upiu_flags, enum dma_data_direction cmd_dir) + u32 *upiu_flags, enum dma_data_direction cmd_dir) { struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr; u32 data_direction; @@ -1299,47 +1299,55 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) } /** - * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU) + * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU) + * for Device Management Purposes * @hba - per adapter instance * @lrb - pointer to local reference block */ -static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { u32 upiu_flags; int ret = 0; - switch (lrbp->command_type) { - case UTP_CMD_TYPE_SCSI: - if (likely(lrbp->cmd)) { - ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, - lrbp->cmd->sc_data_direction); - ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); - } else { - ret = -EINVAL; - } - break; - case UTP_CMD_TYPE_DEV_MANAGE: - ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE); - if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY) - ufshcd_prepare_utp_query_req_upiu( - hba, lrbp, upiu_flags); - else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) - ufshcd_prepare_utp_nop_upiu(lrbp); - else - ret = -EINVAL; - break; - case UTP_CMD_TYPE_UFS: - /* For UFS native command implementation */ - ret = -ENOTSUPP; - dev_err(hba->dev, "%s: UFS native command are not supported\n", - __func__); - break; - default: - ret = -ENOTSUPP; - dev_err(hba->dev, "%s: unknown command type: 0x%x\n", - __func__, lrbp->command_type); - break; - } /* end of switch */ + if (hba->ufs_version == UFSHCI_VERSION_20) + lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; + else + lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE; + + ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE); + if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY) + ufshcd_prepare_utp_query_req_upiu(hba, lrbp, upiu_flags); + else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) + ufshcd_prepare_utp_nop_upiu(lrbp); + else + ret = -EINVAL; + + return ret; +} + +/** + * ufshcd_comp_scsi_upiu - UFS Protocol Information Unit(UPIU) + * for SCSI Purposes + * @hba - per adapter instance + * @lrb - pointer to local reference block + */ +static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + u32 upiu_flags; + int ret = 0; + + if (hba->ufs_version == UFSHCI_VERSION_20) + lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; + else + lrbp->command_type = UTP_CMD_TYPE_SCSI; + + if (likely(lrbp->cmd)) { + ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, + lrbp->cmd->sc_data_direction); + ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); + } else { + ret = -EINVAL; + } return ret; } @@ -1451,10 +1459,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) lrbp->task_tag = tag; lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false; - lrbp->command_type = UTP_CMD_TYPE_SCSI; - /* form UPIU before issuing the command */ - ufshcd_compose_upiu(hba, lrbp); + ufshcd_comp_scsi_upiu(hba, lrbp); + err = ufshcd_map_sg(lrbp); if (err) { lrbp->cmd = NULL; @@ -1479,11 +1486,10 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba, lrbp->sense_buffer = NULL; lrbp->task_tag = tag; lrbp->lun = 0; /* device management cmd is not specific to any LUN */ - lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE; lrbp->intr_cmd = true; /* No interrupt aggregation */ hba->dev_cmd.type = cmd_type; - return ufshcd_compose_upiu(hba, lrbp); + return ufshcd_comp_devman_upiu(hba, lrbp); } static int @@ -3539,7 +3545,8 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); __ufshcd_release(hba); - } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { + } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || + lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { if (hba->dev_cmd.complete) complete(hba->dev_cmd.complete); } diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 4cb1cc63f1a1..36f58795c601 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -279,6 +279,11 @@ enum { UTP_CMD_TYPE_DEV_MANAGE = 0x2, }; +/* To accommodate UFS2.0 required Command type */ +enum { + UTP_CMD_TYPE_UFS_STORAGE = 0x1, +}; + enum { UTP_SCSI_COMMAND = 0x00000000, UTP_NATIVE_UFS_COMMAND = 0x10000000, From 87ee1a81644b4602fcf9618ab851ad514b139be8 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:28 +0100 Subject: [PATCH 004/101] ufs: add unipro attributes Add unipro attributes. Signed-off-by: Joao Pinto Acked-by: Tomas Winkler Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/unipro.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index e2854e45f8d3..eff8b5675575 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -36,6 +36,10 @@ #define TX_LCC_SEQUENCER 0x0032 #define TX_MIN_ACTIVATETIME 0x0033 #define TX_PWM_G6_G7_SYNC_LENGTH 0x0034 +#define TX_REFCLKFREQ 0x00EB +#define TX_CFGCLKFREQVAL 0x00EC +#define CFGEXTRATTR 0x00F0 +#define DITHERCTRL2 0x00F1 /* * M-RX Configuration Attributes @@ -51,10 +55,40 @@ #define RX_TERMINATION_FORCE_ENABLE 0x0089 #define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F #define RX_HIBERN8TIME_CAPABILITY 0x0092 +#define RX_REFCLKFREQ 0x00EB +#define RX_CFGCLKFREQVAL 0x00EC +#define CFGWIDEINLN 0x00F0 +#define CFGRXCDR8 0x00BA +#define ENARXDIRECTCFG4 0x00F2 +#define CFGRXOVR8 0x00BD +#define RXDIRECTCTRL2 0x00C7 +#define ENARXDIRECTCFG3 0x00F3 +#define RXCALCTRL 0x00B4 +#define ENARXDIRECTCFG2 0x00F4 +#define CFGRXOVR4 0x00E9 +#define RXSQCTRL 0x00B5 +#define CFGRXOVR6 0x00BF #define is_mphy_tx_attr(attr) (attr < RX_MODE) #define RX_MIN_ACTIVATETIME_UNIT_US 100 #define HIBERN8TIME_UNIT_US 100 + +/* + * Common Block Attributes + */ +#define TX_GLOBALHIBERNATE UNIPRO_CB_OFFSET(0x002B) +#define REFCLKMODE UNIPRO_CB_OFFSET(0x00BF) +#define DIRECTCTRL19 UNIPRO_CB_OFFSET(0x00CD) +#define DIRECTCTRL10 UNIPRO_CB_OFFSET(0x00E6) +#define CDIRECTCTRL6 UNIPRO_CB_OFFSET(0x00EA) +#define RTOBSERVESELECT UNIPRO_CB_OFFSET(0x00F0) +#define CBDIVFACTOR UNIPRO_CB_OFFSET(0x00F1) +#define CBDCOCTRL5 UNIPRO_CB_OFFSET(0x00F3) +#define CBPRGPLL2 UNIPRO_CB_OFFSET(0x00F8) +#define CBPRGTUNING UNIPRO_CB_OFFSET(0x00FB) + +#define UNIPRO_CB_OFFSET(x) (0x8000 | x) + /* * PHY Adpater attributes */ @@ -119,6 +153,11 @@ #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 +/*Other attributes*/ +#define VS_MPHYCFGUPDT 0xD085 +#define VS_DEBUGOMC 0xD09E +#define VS_POWERSTATE 0xD083 + /* PHY Adapter Protocol Constants */ #define PA_MAXDATALANES 4 From 79fcc03349b5766dbd15b169c762b442296fbf6b Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:29 +0100 Subject: [PATCH 005/101] ufs: add link status to ufshci Add link status to ufshci. Signed-off-by: Joao Pinto Acked-by: Tomas Winkler Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshci.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 36f58795c601..9599741ff606 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -220,6 +220,12 @@ enum { #define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16) #define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF) +/* Link Status*/ +enum link_status { + UFSHCD_LINK_IS_DOWN = 1, + UFSHCD_LINK_IS_UP = 2, +}; + /* UIC Commands */ enum uic_cmd_dme { UIC_CMD_DME_GET = 0x01, From 4b9ffb5a353bdee49f1f477ffe2b95ab3f9cbc0c Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:30 +0100 Subject: [PATCH 006/101] ufs: add support for DesignWare Controller This patch has the goal to add support for DesignWare UFS Controller specific operations. Signed-off-by: Joao Pinto Reviewed-by: Hannes Reinicke Signed-off-by: Martin K. Petersen --- MAINTAINERS | 6 ++ drivers/scsi/ufs/ufshcd-dwc.c | 150 ++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd-dwc.h | 26 ++++++ drivers/scsi/ufs/ufshcd.h | 7 ++ drivers/scsi/ufs/ufshci-dwc.h | 36 ++++++++ 5 files changed, 225 insertions(+) create mode 100644 drivers/scsi/ufs/ufshcd-dwc.c create mode 100644 drivers/scsi/ufs/ufshcd-dwc.h create mode 100644 drivers/scsi/ufs/ufshci-dwc.h diff --git a/MAINTAINERS b/MAINTAINERS index 1209323b7e43..368121753b85 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11770,6 +11770,12 @@ S: Supported F: Documentation/scsi/ufs.txt F: drivers/scsi/ufs/ +UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS +M: Joao Pinto +L: linux-scsi@vger.kernel.org +S: Supported +F: drivers/scsi/ufs/*dwc* + UNSORTED BLOCK IMAGES (UBI) M: Artem Bityutskiy M: Richard Weinberger diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c new file mode 100644 index 000000000000..9b3ca7f15d35 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -0,0 +1,150 @@ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "ufshcd.h" +#include "unipro.h" + +#include "ufshcd-dwc.h" +#include "ufshci-dwc.h" + +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, + const struct ufshcd_dme_attr_val *v, int n) +{ + int ret = 0; + int attr_node = 0; + + for (attr_node = 0; attr_node < n; attr_node++) { + ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel, + ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer); + + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs); + +/** + * ufshcd_dwc_program_clk_div() + * This function programs the clk divider value. This value is needed to + * provide 1 microsecond tick to unipro layer. + * @hba: Private Structure pointer + * @divider_val: clock divider value to be programmed + * + */ +static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) +{ + ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV); +} + +/** + * ufshcd_dwc_link_is_up() + * Check if link is up + * @hba: private structure poitner + * + * Returns 0 on success, non-zero value on failure + */ +static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) +{ + int dme_result = 0; + + ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result); + + if (dme_result == UFSHCD_LINK_IS_UP) { + ufshcd_set_link_active(hba); + return 0; + } + + return 1; +} + +/** + * ufshcd_dwc_connection_setup() + * This function configures both the local side (host) and the peer side + * (device) unipro attributes to establish the connection to application/ + * cport. + * This function is not required if the hardware is properly configured to + * have this connection setup on reset. But invoking this function does no + * harm and should be fine even working with any ufs device. + * + * @hba: pointer to drivers private data + * + * Returns 0 on success non-zero value on failure + */ +static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) +{ + const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_LOCAL }, + { UIC_ARG_MIB(T_CPORTMODE), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_PEER }, + { UIC_ARG_MIB(N_DEVICEID), 1, DME_PEER }, + { UIC_ARG_MIB(N_DEVICEID_VALID), 1, DME_PEER }, + { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_PEER }, + { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_PEER }, + { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_PEER }, + { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_PEER }, + { UIC_ARG_MIB(T_CPORTMODE), 1, DME_PEER }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_PEER } + }; + + return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, ARRAY_SIZE(setup_attrs)); +} + +/** + * ufshcd_dwc_link_startup_notify() + * UFS Host DWC specific link startup sequence + * @hba: private structure poitner + * @status: Callback notify status + * + * Returns 0 on success, non-zero value on failure + */ +int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + int err = 0; + + if (status == PRE_CHANGE) { + ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125); + + if (hba->vops->phy_initialization) { + err = hba->vops->phy_initialization(hba); + if (err) { + dev_err(hba->dev, "Phy setup failed (%d)\n", + err); + goto out; + } + } + } else { /* POST_CHANGE */ + err = ufshcd_dwc_link_is_up(hba); + if (err) { + dev_err(hba->dev, "Link is not up\n"); + goto out; + } + + err = ufshcd_dwc_connection_setup(hba); + if (err) + dev_err(hba->dev, "Connection setup failed (%d)\n", + err); + } + +out: + return err; +} +EXPORT_SYMBOL(ufshcd_dwc_link_startup_notify); diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h new file mode 100644 index 000000000000..c8be295e0ebe --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-dwc.h @@ -0,0 +1,26 @@ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _UFSHCD_DWC_H +#define _UFSHCD_DWC_H + +struct ufshcd_dme_attr_val { + u32 attr_sel; + u32 mib_val; + u8 peer; +}; + +int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status); +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, + const struct ufshcd_dme_attr_val *v, int n); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 4bb65669f052..430bef111293 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -264,6 +264,7 @@ struct ufs_pwr_mode_info { * @suspend: called during host controller PM callback * @resume: called during host controller PM callback * @dbg_register_dump: used to dump controller debug information + * @phy_initialization: used to initialize phys */ struct ufs_hba_variant_ops { const char *name; @@ -285,6 +286,7 @@ struct ufs_hba_variant_ops { int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); void (*dbg_register_dump)(struct ufs_hba *hba); + int (*phy_initialization)(struct ufs_hba *); }; /* clock gating state */ @@ -567,11 +569,16 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba) static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba) { +/* DWC UFS Core has the Interrupt aggregation feature but is not detectable*/ +#ifndef CONFIG_SCSI_UFS_DWC if ((hba->caps & UFSHCD_CAP_INTR_AGGR) && !(hba->quirks & UFSHCD_QUIRK_BROKEN_INTR_AGGR)) return true; else return false; +#else +return true; +#endif } #define ufshcd_writel(hba, val, reg) \ diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h new file mode 100644 index 000000000000..ca341fece310 --- /dev/null +++ b/drivers/scsi/ufs/ufshci-dwc.h @@ -0,0 +1,36 @@ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _UFSHCI_DWC_H +#define _UFSHCI_DWC_H + +/* DWC HC UFSHCI specific Registers */ +enum dwc_specific_registers { + DWC_UFS_REG_HCLKDIV = 0xFC, +}; + +/* Clock Divider Values: Hex equivalent of frequency in MHz */ +enum clk_div_values { + DWC_UFS_REG_HCLKDIV_DIV_62_5 = 0x3e, + DWC_UFS_REG_HCLKDIV_DIV_125 = 0x7d, + DWC_UFS_REG_HCLKDIV_DIV_200 = 0xc8, +}; + +/* Selector Index */ +enum selector_index { + SELIND_LN0_TX = 0x00, + SELIND_LN1_TX = 0x01, + SELIND_LN0_RX = 0x04, + SELIND_LN1_RX = 0x05, +}; + +#endif /* End of Header */ From 947e7013c7b99549c0771b38277327e68dab4709 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:31 +0100 Subject: [PATCH 007/101] ufs: add support for Synopsys G210 Test Chip This patch adds support for Synopsys G210 Test Chip. Signed-off-by: Joao Pinto Reviewed-by: Hannes Reinicke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/tc-dwc-g210.c | 315 +++++++++++++++++++++++++++++++++ drivers/scsi/ufs/tc-dwc-g210.h | 19 ++ 2 files changed, 334 insertions(+) create mode 100644 drivers/scsi/ufs/tc-dwc-g210.c create mode 100644 drivers/scsi/ufs/tc-dwc-g210.h diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c new file mode 100644 index 000000000000..181f208f85ad --- /dev/null +++ b/drivers/scsi/ufs/tc-dwc-g210.c @@ -0,0 +1,315 @@ +/* + * Synopsys G210 Test Chip driver + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "ufshcd.h" +#include "unipro.h" + +#include "ufshcd-dwc.h" +#include "ufshci-dwc.h" + +/** + * tc_dwc_g210_setup_40bit_rmmi() + * This function configures Synopsys TC specific atributes (40-bit RMMI) + * @hba: Pointer to drivers structure + * + * Returns 0 on success or non-zero value on failure + */ +static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba) +{ + const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL }, + { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL }, + { UIC_ARG_MIB(CDIRECTCTRL6), 0x80, DME_LOCAL }, + { UIC_ARG_MIB(CBDIVFACTOR), 0x08, DME_LOCAL }, + { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL }, + { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL }, + { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL }, + { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x14, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 4, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, + DME_LOCAL }, + { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL }, + { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, + DME_LOCAL }, + { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL }, + }; + + return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, + ARRAY_SIZE(setup_attrs)); +} + +/** + * tc_dwc_g210_setup_20bit_rmmi_lane0() + * This function configures Synopsys TC 20-bit RMMI Lane 0 + * @hba: Pointer to drivers structure + * + * Returns 0 on success or non-zero value on failure + */ +static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba) +{ + const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x12, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 2, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, + DME_LOCAL }, + { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL }, + { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, + DME_LOCAL }, + { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL }, + }; + + return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, + ARRAY_SIZE(setup_attrs)); +} + +/** + * tc_dwc_g210_setup_20bit_rmmi_lane1() + * This function configures Synopsys TC 20-bit RMMI Lane 1 + * @hba: Pointer to drivers structure + * + * Returns 0 on success or non-zero value on failure + */ +static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba) +{ + int connected_rx_lanes = 0; + int connected_tx_lanes = 0; + int ret = 0; + + const struct ufshcd_dme_attr_val setup_tx_attrs[] = { + { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN1_TX), 0x0d, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN1_TX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN1_TX), 0x12, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, + DME_LOCAL }, + }; + + const struct ufshcd_dme_attr_val setup_rx_attrs[] = { + { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN1_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN1_RX), 0x19, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN1_RX), 2, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN1_RX), 0x80, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN1_RX), 0x03, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN1_RX), 0x16, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN1_RX), 0x42, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN1_RX), 0xa4, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN1_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN1_RX), 0x01, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN1_RX), 0x28, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN1_RX), 0x1E, + DME_LOCAL }, + { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN1_RX), 0x2f, + DME_LOCAL }, + }; + + /* Get the available lane count */ + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), + &connected_rx_lanes); + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &connected_tx_lanes); + + if (connected_tx_lanes == 2) { + + ret = ufshcd_dwc_dme_set_attrs(hba, setup_tx_attrs, + ARRAY_SIZE(setup_tx_attrs)); + + if (ret) + goto out; + } + + if (connected_rx_lanes == 2) { + ret = ufshcd_dwc_dme_set_attrs(hba, setup_rx_attrs, + ARRAY_SIZE(setup_rx_attrs)); + } + +out: + return ret; +} + +/** + * tc_dwc_g210_setup_20bit_rmmi() + * This function configures Synopsys TC specific atributes (20-bit RMMI) + * @hba: Pointer to drivers structure + * + * Returns 0 on success or non-zero value on failure + */ +static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba) +{ + int ret = 0; + + const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL }, + { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL }, + { UIC_ARG_MIB(CDIRECTCTRL6), 0xc0, DME_LOCAL }, + { UIC_ARG_MIB(CBDIVFACTOR), 0x44, DME_LOCAL }, + { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL }, + { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL }, + { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL }, + }; + + ret = ufshcd_dwc_dme_set_attrs(hba, setup_attrs, + ARRAY_SIZE(setup_attrs)); + if (ret) + goto out; + + /* Lane 0 configuration*/ + ret = tc_dwc_g210_setup_20bit_rmmi_lane0(hba); + if (ret) + goto out; + + /* Lane 1 configuration*/ + ret = tc_dwc_g210_setup_20bit_rmmi_lane1(hba); + if (ret) + goto out; + +out: + return ret; +} + +/** + * tc_dwc_g210_config_40_bit() + * This function configures Local (host) Synopsys 40-bit TC specific attributes + * + * @hba: Pointer to drivers structure + * + * Returns 0 on success non-zero value on failure + */ +int tc_dwc_g210_config_40_bit(struct ufs_hba *hba) +{ + int ret = 0; + + dev_info(hba->dev, "Configuring Test Chip 40-bit RMMI\n"); + ret = tc_dwc_g210_setup_40bit_rmmi(hba); + if (ret) { + dev_err(hba->dev, "Configuration failed\n"); + goto out; + } + + /* To write Shadow register bank to effective configuration block */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); + if (ret) + goto out; + + /* To configure Debug OMC */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01); + +out: + return ret; +} +EXPORT_SYMBOL(tc_dwc_g210_config_40_bit); + +/** + * tc_dwc_g210_config_20_bit() + * This function configures Local (host) Synopsys 20-bit TC specific attributes + * + * @hba: Pointer to drivers structure + * + * Returns 0 on success non-zero value on failure + */ +int tc_dwc_g210_config_20_bit(struct ufs_hba *hba) +{ + int ret = 0; + + dev_info(hba->dev, "Configuring Test Chip 20-bit RMMI\n"); + ret = tc_dwc_g210_setup_20bit_rmmi(hba); + if (ret) { + dev_err(hba->dev, "Configuration failed\n"); + goto out; + } + + /* To write Shadow register bank to effective configuration block */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); + if (ret) + goto out; + + /* To configure Debug OMC */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01); + +out: + return ret; +} +EXPORT_SYMBOL(tc_dwc_g210_config_20_bit); diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h new file mode 100644 index 000000000000..fb177db1227d --- /dev/null +++ b/drivers/scsi/ufs/tc-dwc-g210.h @@ -0,0 +1,19 @@ +/* + * Synopsys G210 Test Chip driver + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TC_DWC_G210_H +#define _TC_DWC_G210_H + +int tc_dwc_g210_config_40_bit(struct ufs_hba *hba); +int tc_dwc_g210_config_20_bit(struct ufs_hba *hba); + +#endif /* End of Header */ From fc040a3fc47cad038f774275ea61fe6d5b57d7cc Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:32 +0100 Subject: [PATCH 008/101] ufs: add TC G210 platform driver This patch adds a glue platform driver for the Synopsys G210 Test Chip. Signed-off-by: Joao Pinto Reviewed-by: Hannes Reinicke Signed-off-by: Martin K. Petersen --- .../bindings/ufs/tc-dwc-g210-pltfrm.txt | 26 ++++ drivers/scsi/ufs/Kconfig | 8 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/tc-dwc-g210-pltfrm.c | 113 ++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt create mode 100644 drivers/scsi/ufs/tc-dwc-g210-pltfrm.c diff --git a/Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt b/Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt new file mode 100644 index 000000000000..71c0777960e9 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt @@ -0,0 +1,26 @@ +* Universal Flash Storage (UFS) DesignWare Host Controller + +DWC_UFS nodes are defined to describe on-chip UFS host controllers and MPHY. +Each UFS controller instance should have its own node. + +Required properties: +- compatible : compatible list must contain the PHY type & version: + "snps,g210-tc-6.00-20bit" + "snps,g210-tc-6.00-40bit" + complemented with the Controller IP version: + "snps,dwc-ufshcd-1.40a" + complemented with the JEDEC version: + "jedec,ufs-1.1" + "jedec,ufs-2.0" + +- reg : +- interrupts : + +Example for a setup using a 1.40a DWC Controller with a 6.00 G210 40-bit TC: + dwc-ufs@d0000000 { + compatible = "snps,g210-tc-6.00-40bit", + "snps,dwc-ufshcd-1.40a", + "jedec,ufs-2.0"; + reg = < 0xd0000000 0x10000 >; + interrupts = < 24 >; + }; diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 097894a1fab5..81fdfb376ea5 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -72,6 +72,14 @@ config SCSI_UFSHCD_PLATFORM If unsure, say N. +config SCSI_UFS_DWC_TC_PLATFORM + tristate "DesignWare platform support using a G210 Test Chip" + depends on SCSI_UFSHCD_PLATFORM + ---help--- + Synopsys Test Chip is a PHY for prototyping purposes. + + If unsure, say N. + config SCSI_UFS_QCOM tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 8303bcce7a23..d5774c64a0bb 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -1,4 +1,5 @@ # UFSHCD makefile +obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c new file mode 100644 index 000000000000..2d3f5270f875 --- /dev/null +++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c @@ -0,0 +1,113 @@ +/* + * Synopsys G210 Test Chip driver + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include "ufshcd-pltfrm.h" +#include "ufshcd-dwc.h" +#include "tc-dwc-g210.h" + +/** + * UFS DWC specific variant operations + */ +static struct ufs_hba_variant_ops tc_dwc_g210_20bit_pltfm_hba_vops = { + .name = "tc-dwc-g210-pltfm", + .link_startup_notify = ufshcd_dwc_link_startup_notify, + .phy_initialization = tc_dwc_g210_config_20_bit, +}; + +static struct ufs_hba_variant_ops tc_dwc_g210_40bit_pltfm_hba_vops = { + .name = "tc-dwc-g210-pltfm", + .link_startup_notify = ufshcd_dwc_link_startup_notify, + .phy_initialization = tc_dwc_g210_config_40_bit, +}; + +static const struct of_device_id tc_dwc_g210_pltfm_match[] = { + { + .compatible = "snps,g210-tc-6.00-20bit", + .data = &tc_dwc_g210_20bit_pltfm_hba_vops, + }, + { + .compatible = "snps,g210-tc-6.00-40bit", + .data = &tc_dwc_g210_40bit_pltfm_hba_vops, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, tc_dwc_g210_pltfm_match); + +/** + * tc_dwc_g210_pltfm_probe() + * @pdev: pointer to platform device structure + * + */ +static int tc_dwc_g210_pltfm_probe(struct platform_device *pdev) +{ + int err; + const struct of_device_id *of_id; + struct ufs_hba_variant_ops *vops; + struct device *dev = &pdev->dev; + + of_id = of_match_node(tc_dwc_g210_pltfm_match, dev->of_node); + vops = (struct ufs_hba_variant_ops *)of_id->data; + + /* Perform generic probe */ + err = ufshcd_pltfrm_init(pdev, vops); + if (err) + dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); + + return err; +} + +/** + * tc_dwc_g210_pltfm_remove() + * @pdev: pointer to platform device structure + * + */ +static int tc_dwc_g210_pltfm_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + + return 0; +} + +static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = { + .suspend = ufshcd_pltfrm_suspend, + .resume = ufshcd_pltfrm_resume, + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, + .runtime_resume = ufshcd_pltfrm_runtime_resume, + .runtime_idle = ufshcd_pltfrm_runtime_idle, +}; + +static struct platform_driver tc_dwc_g210_pltfm_driver = { + .probe = tc_dwc_g210_pltfm_probe, + .remove = tc_dwc_g210_pltfm_remove, + .shutdown = ufshcd_pltfrm_shutdown, + .driver = { + .name = "tc-dwc-g210-pltfm", + .pm = &tc_dwc_g210_pltfm_pm_ops, + .of_match_table = of_match_ptr(tc_dwc_g210_pltfm_match), + }, +}; + +module_platform_driver(tc_dwc_g210_pltfm_driver); + +MODULE_ALIAS("platform:tc-dwc-g210-pltfm"); +MODULE_DESCRIPTION("Synopsys Test Chip G210 platform glue driver"); +MODULE_AUTHOR("Joao Pinto "); +MODULE_LICENSE("Dual BSD/GPL"); From ec658ea0c548f4c5cb5a6efad692bae571382f05 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 11 May 2016 12:21:33 +0100 Subject: [PATCH 009/101] ufs: add TC G210 pci driver This patch adds a glue pci driver for the Synopsys G210 Test Chip. [mkp: Fixed Kconfig depends and module name] Signed-off-by: Joao Pinto Reviewed-by: Hannes Reinicke Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 8 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/tc-dwc-g210-pci.c | 181 +++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 drivers/scsi/ufs/tc-dwc-g210-pci.c diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 81fdfb376ea5..47966909286d 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -61,6 +61,14 @@ config SCSI_UFSHCD_PCI If unsure, say N. +config SCSI_UFS_DWC_TC_PCI + tristate "DesignWare pci support using a G210 Test Chip" + depends on SCSI_UFSHCD && PCI + ---help--- + Synopsys Test Chip is a PHY for prototyping purposes. + + If unsure, say N. + config SCSI_UFSHCD_PLATFORM tristate "Platform bus based UFS Controller support" depends on SCSI_UFSHCD diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index d5774c64a0bb..6e77cb0bfee9 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -1,4 +1,5 @@ # UFSHCD makefile +obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c new file mode 100644 index 000000000000..c09a0fef0fe6 --- /dev/null +++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c @@ -0,0 +1,181 @@ +/* + * Synopsys G210 Test Chip driver + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "ufshcd.h" +#include "ufshcd-dwc.h" +#include "tc-dwc-g210.h" + +#include +#include + +/* Test Chip type expected values */ +#define TC_G210_20BIT 20 +#define TC_G210_40BIT 40 +#define TC_G210_INV 0 + +static int tc_type = TC_G210_INV; +module_param(tc_type, int, 0); +MODULE_PARM_DESC(tc_type, "Test Chip Type (20 = 20-bit, 40 = 40-bit)"); + +static int tc_dwc_g210_pci_suspend(struct device *dev) +{ + return ufshcd_system_suspend(dev_get_drvdata(dev)); +} + +static int tc_dwc_g210_pci_resume(struct device *dev) +{ + return ufshcd_system_resume(dev_get_drvdata(dev)); +} + +static int tc_dwc_g210_pci_runtime_suspend(struct device *dev) +{ + return ufshcd_runtime_suspend(dev_get_drvdata(dev)); +} + +static int tc_dwc_g210_pci_runtime_resume(struct device *dev) +{ + return ufshcd_runtime_resume(dev_get_drvdata(dev)); +} + +static int tc_dwc_g210_pci_runtime_idle(struct device *dev) +{ + return ufshcd_runtime_idle(dev_get_drvdata(dev)); +} + +/** + * struct ufs_hba_dwc_vops - UFS DWC specific variant operations + */ +static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = { + .name = "tc-dwc-g210-pci", + .link_startup_notify = ufshcd_dwc_link_startup_notify, +}; + +/** + * tc_dwc_g210_pci_shutdown - main function to put the controller in reset state + * @pdev: pointer to PCI device handle + */ +static void tc_dwc_g210_pci_shutdown(struct pci_dev *pdev) +{ + ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev)); +} + +/** + * tc_dwc_g210_pci_remove - de-allocate PCI/SCSI host and host memory space + * data structure memory + * @pdev - pointer to PCI handle + */ +static void tc_dwc_g210_pci_remove(struct pci_dev *pdev) +{ + struct ufs_hba *hba = pci_get_drvdata(pdev); + + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + ufshcd_remove(hba); +} + +/** + * tc_dwc_g210_pci_probe - probe routine of the driver + * @pdev: pointer to PCI device handle + * @id: PCI device id + * + * Returns 0 on success, non-zero value on failure + */ +static int +tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ufs_hba *hba; + void __iomem *mmio_base; + int err; + + /* Check Test Chip type and set the specific setup routine */ + if (tc_type == TC_G210_20BIT) { + tc_dwc_g210_pci_hba_vops.phy_initialization = + tc_dwc_g210_config_20_bit; + } else if (tc_type == TC_G210_40BIT) { + tc_dwc_g210_pci_hba_vops.phy_initialization = + tc_dwc_g210_config_40_bit; + } else { + dev_err(&pdev->dev, "test chip version not specified\n"); + return -EPERM; + } + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "pcim_enable_device failed\n"); + return err; + } + + pci_set_master(pdev); + + err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD); + if (err < 0) { + dev_err(&pdev->dev, "request and iomap failed\n"); + return err; + } + + mmio_base = pcim_iomap_table(pdev)[0]; + + err = ufshcd_alloc_host(&pdev->dev, &hba); + if (err) { + dev_err(&pdev->dev, "Allocation failed\n"); + return err; + } + + INIT_LIST_HEAD(&hba->clk_list_head); + + hba->vops = &tc_dwc_g210_pci_hba_vops; + + err = ufshcd_init(hba, mmio_base, pdev->irq); + if (err) { + dev_err(&pdev->dev, "Initialization failed\n"); + return err; + } + + pci_set_drvdata(pdev, hba); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = { + .suspend = tc_dwc_g210_pci_suspend, + .resume = tc_dwc_g210_pci_resume, + .runtime_suspend = tc_dwc_g210_pci_runtime_suspend, + .runtime_resume = tc_dwc_g210_pci_runtime_resume, + .runtime_idle = tc_dwc_g210_pci_runtime_idle, +}; + +static const struct pci_device_id tc_dwc_g210_pci_tbl[] = { + { PCI_VENDOR_ID_SYNOPSYS, 0xB101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYNOPSYS, 0xB102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { } /* terminate list */ +}; + +MODULE_DEVICE_TABLE(pci, tc_dwc_g210_pci_tbl); + +static struct pci_driver tc_dwc_g210_pci_driver = { + .name = "tc-dwc-g210-pci", + .id_table = tc_dwc_g210_pci_tbl, + .probe = tc_dwc_g210_pci_probe, + .remove = tc_dwc_g210_pci_remove, + .shutdown = tc_dwc_g210_pci_shutdown, + .driver = { + .pm = &tc_dwc_g210_pci_pm_ops + }, +}; + +module_pci_driver(tc_dwc_g210_pci_driver); + +MODULE_AUTHOR("Joao Pinto "); +MODULE_DESCRIPTION("Synopsys Test Chip G210 PCI glue driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 075892d7a2acab7d21a286a2b6db0e6702331bd2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 17 May 2016 16:38:40 +0200 Subject: [PATCH 010/101] snic: fix typo firmare -> firmware Signed-off-by: Julia Lawall Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_fwint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/snic/snic_fwint.h b/drivers/scsi/snic/snic_fwint.h index c5f9e1917a8e..2a045a57e365 100644 --- a/drivers/scsi/snic/snic_fwint.h +++ b/drivers/scsi/snic/snic_fwint.h @@ -92,7 +92,7 @@ enum snic_io_status { }; /* end of enum snic_io_status */ /* - * snic_io_hdr : host <--> firmare + * snic_io_hdr : host <--> firmware * * for any other message that will be queued to firmware should * have the following request header From 014e8ba76ec3d6e75ab1811ea471e647a0b5dd92 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 17 May 2016 16:38:44 +0200 Subject: [PATCH 011/101] pm8001: fix typo firmare -> firmware Signed-off-by: Julia Lawall Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 6bd7bf4f4a81..9fc675f57e33 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1249,7 +1249,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev) /* Chip documentation for the 8070 and 8072 SPCv */ /* states that a 500ms minimum delay is required */ - /* before issuing commands. Otherwise, the firmare */ + /* before issuing commands. Otherwise, the firmware */ /* will enter an unrecoverable state. */ if (pm8001_ha->chip_id == chip_8070 || From 22e9f5a61666ed1145a09fbe49ac1a6f2ae7be8e Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Thu, 19 May 2016 19:38:33 +0530 Subject: [PATCH 012/101] aacraid: use kmemdup Use kmemdup when some other buffer is immediately copied into allocated region. It replaces call to allocation followed by memcpy, by a single call to kmemdup. Signed-off-by: Muhammad Falak R Wani Reviewed-by: Raghava Aditya Renukunta Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/commctrl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 4b3bb52b5108..b381b3718a98 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -635,15 +635,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) } } else { struct user_sgmap* usg; - usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap), GFP_KERNEL); + usg = kmemdup(upsg, + actual_fibsize - sizeof(struct aac_srb) + + sizeof(struct sgmap), GFP_KERNEL); if (!usg) { dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); rcode = -ENOMEM; goto cleanup; } - memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap)); actual_fibsize = actual_fibsize64; for (i = 0; i < usg->count; i++) { From 2c99a3142e6d70070bd4a2bfa73378007b36e230 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:06:19 +0200 Subject: [PATCH 013/101] MAINTAINERS: Add file patterns for scsi device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: linux-scsi@vger.kernel.org Signed-off-by: Martin K. Petersen --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 368121753b85..ee90806ff1c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10137,6 +10137,7 @@ M: "Martin K. Petersen" T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git L: linux-scsi@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/scsi/ F: drivers/scsi/ F: include/scsi/ From 87ee3ab928dc4a3723005c5b553775e9acf479c1 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Mon, 23 May 2016 10:18:07 +0100 Subject: [PATCH 014/101] ufs: Adding license info do tc-dwc-g210 and ufshcd-dwc to enable loadable module This patch adds license info to the tc-dwc-g210 and ufshcd-dwc files in order for them to have access to some ufshcd symbols when all are built as modules. Signed-off-by: Joao Pinto Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/tc-dwc-g210.c | 4 ++++ drivers/scsi/ufs/ufshcd-dwc.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c index 181f208f85ad..d6c5388d41ac 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.c +++ b/drivers/scsi/ufs/tc-dwc-g210.c @@ -313,3 +313,7 @@ out: return ret; } EXPORT_SYMBOL(tc_dwc_g210_config_20_bit); + +MODULE_AUTHOR("Joao Pinto "); +MODULE_DESCRIPTION("Synopsys G210 Test Chip driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c index 9b3ca7f15d35..5fd16c72207f 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.c +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -148,3 +148,7 @@ out: return err; } EXPORT_SYMBOL(ufshcd_dwc_link_startup_notify); + +MODULE_AUTHOR("Joao Pinto "); +MODULE_DESCRIPTION("UFS Host driver for Synopsys Designware Core"); +MODULE_LICENSE("Dual BSD/GPL"); From 87aa95d4bb77613acaed9724efe07dde9e9bacd7 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Wed, 25 May 2016 15:14:28 -0400 Subject: [PATCH 015/101] mpt3sas: set num_phys after allocating phy[] space In _scsih_sas_host_add, the number of HBA phys are determined and then later used to allocate an array of struct _sas_phy's. If the routine sets ioc->sas_hba.num_phys, but then fails to allocate the ioc->sas_hba.phy array (by kcalloc error or other intermediate error/exit path), ioc->sas_hba is left in a dangerous state: all readers of ioc->sas_hba.phy[] do so by indexing it from 0..ioc->sas_hba.num_phys without checking that the space was ever allocated. Modify _scsih_sas_host_add to set ioc->sas_hba.num_phys only after successfully allocating ioc->sas_hba.phy[]. Signed-off-by: Joe Lawrence Acked-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 6bff13e7afc7..cd6be7be0c5b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4903,13 +4903,22 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) u16 ioc_status; u16 sz; u8 device_missing_delay; + u8 num_phys; - mpt3sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); - if (!ioc->sas_hba.num_phys) { + mpt3sas_config_get_number_hba_phys(ioc, &num_phys); + if (!num_phys) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return; } + ioc->sas_hba.phy = kcalloc(num_phys, + sizeof(struct _sas_phy), GFP_KERNEL); + if (!ioc->sas_hba.phy) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc->sas_hba.num_phys = num_phys; /* sas_iounit page 0 */ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * @@ -4969,13 +4978,6 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; - ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); - if (!ioc->sas_hba.phy) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } for (i = 0; i < ioc->sas_hba.num_phys ; i++) { if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, i))) { From ad2bf16543622594432439cd16e90e22cc965964 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Wed, 25 May 2016 15:14:29 -0400 Subject: [PATCH 016/101] mpt3sas: avoid mpt3sas_transport_port_add NULL parent_dev If _scsih_sas_host_add's call to mpt3sas_config_get_sas_iounit_pg0 fails, ioc->sas_hba.parent_dev may be left uninitialized. A later device probe could invoke mpt3sas_transport_port_add which will call sas_port_alloc_num [scsi_transport_sas] with a NULL parent_dev pointer. Signed-off-by: Joe Lawrence Acked-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_transport.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 6a84b82d71bb..ff93286bc32f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -705,6 +705,11 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, goto out_fail; } + if (!sas_node->parent_dev) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_fail; + } port = sas_port_alloc_num(sas_node->parent_dev); if ((sas_port_add(port))) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", From 8a30a3c7e67567075aabe135136423b3c7d19042 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Mon, 30 May 2016 10:41:01 +0200 Subject: [PATCH 017/101] bnx2fc: replace printk() with BNX2FC_IO_DBG() The "fcp_rsp_code = %d" message isn't an error, it's meant to be informative only. This patch prevents a flood of such messages in some situations. Signed-off-by: Maurizio Lombardi Tested-by: Laurence Oberman Reviewed-by: Johannes Thumshirn Acked-by: Chad Dupuis Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 026f394a3851..8f24d60f09d7 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1758,7 +1758,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) { /* Only for task management function */ io_req->fcp_rsp_code = rq_data[3]; - printk(KERN_ERR PFX "fcp_rsp_code = %d\n", + BNX2FC_IO_DBG(io_req, "fcp_rsp_code = %d\n", io_req->fcp_rsp_code); } From 84b342c0f4dc0180ad4ac701b46024761ff4af11 Mon Sep 17 00:00:00 2001 From: Cathy Avery Date: Mon, 23 May 2016 10:29:17 -0400 Subject: [PATCH 018/101] scsi: storvsc: Filter out storvsc messages CD-ROM medium not present When a virtual scsi DVD device is present with no image file attached the storvsc driver logs all resulting unnecessary sense errors whenever IO is issued to the device. [storvsc] Sense Key : Not Ready [current] [storvsc] Add. Sense: Medium not present - tray closed [mkp: Fixed whitespace] Signed-off-by: Cathy Avery Reviewed-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 3ddcabb790a8..8ccfc9ea874b 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -966,6 +966,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, if (scmnd->result) { if (scsi_normalize_sense(scmnd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr) && + !(sense_hdr.sense_key == NOT_READY && + sense_hdr.asc == 0x03A) && do_logging(STORVSC_LOGGING_ERROR)) scsi_print_sense_hdr(scmnd->device, "storvsc", &sense_hdr); From 50408712b50f51b086556a59aaae2078d0fa2094 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 31 May 2016 20:38:49 +0800 Subject: [PATCH 019/101] hisi_sas: add v2 hw ACPI support Add support in v2 hw driver for ACPI. A check on whether an ACPI handle is available for the device is used to decide on whether to use ACPI reset handler or syscon for hw reset. Signed-off-by: John Garry Signed-off-by: Wei Xu Reviewed-by: Zhangfei Gao Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 68 ++++++++++++++++---------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index bd20c5488768..7d5edd1f4bba 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -721,30 +721,41 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba) return -EIO; } - /* reset and disable clock*/ - regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg, - reset_val); - regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4, - reset_val); - msleep(1); - regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val); - if (reset_val != (val & reset_val)) { - dev_err(dev, "SAS reset fail.\n"); - return -EIO; - } + if (ACPI_HANDLE(dev)) { + acpi_status s; - /* De-reset and enable clock*/ - regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4, - reset_val); - regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg, - reset_val); - msleep(1); - regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, - &val); - if (val & reset_val) { - dev_err(dev, "SAS de-reset fail.\n"); - return -EIO; - } + s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL); + if (ACPI_FAILURE(s)) { + dev_err(dev, "Reset failed\n"); + return -EIO; + } + } else if (hisi_hba->ctrl) { + /* reset and disable clock*/ + regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg, + reset_val); + regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4, + reset_val); + msleep(1); + regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val); + if (reset_val != (val & reset_val)) { + dev_err(dev, "SAS reset fail.\n"); + return -EIO; + } + + /* De-reset and enable clock*/ + regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4, + reset_val); + regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg, + reset_val); + msleep(1); + regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, + &val); + if (val & reset_val) { + dev_err(dev, "SAS de-reset fail.\n"); + return -EIO; + } + } else + dev_warn(dev, "no reset method\n"); return 0; } @@ -752,13 +763,12 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba) static void init_reg_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = &hisi_hba->pdev->dev; - struct device_node *np = dev->of_node; int i; /* Global registers init */ /* Deal with am-max-transmissions quirk */ - if (of_get_property(np, "hip06-sas-v2-quirk-amt", NULL)) { + if (device_property_present(dev, "hip06-sas-v2-quirk-amt")) { hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020); hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS, 0x2020); @@ -2260,12 +2270,20 @@ static const struct of_device_id sas_v2_of_match[] = { }; MODULE_DEVICE_TABLE(of, sas_v2_of_match); +static const struct acpi_device_id sas_v2_acpi_match[] = { + { "HISI0162", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match); + static struct platform_driver hisi_sas_v2_driver = { .probe = hisi_sas_v2_probe, .remove = hisi_sas_v2_remove, .driver = { .name = DRV_NAME, .of_match_table = sas_v2_of_match, + .acpi_match_table = ACPI_PTR(sas_v2_acpi_match), }, }; From 308d85d1762f48e69584b168afcfef85c907d05a Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 31 May 2016 20:38:50 +0800 Subject: [PATCH 020/101] hisi_sas: fix the inconsistent lock issue reported by CONFIG_PROVE_LOCKING It is not necessary to surround call to notify_port_event(, PORTE_BROADCAST_RCVD) by spin_lock_irqsave(), so remove. This was causing a warn, as below: ================================= [ INFO: inconsistent lock state ] 4.4.8+ #12 Not tainted --------------------------------- inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. kworker/u64:1/168 [HC0[0]:SC0[0]:HE1:SE1] takes: (&(&hisi_hba->lock)->rlock){?.....}, at: [] alloc_dev_quirk_v2_hw+0x48/0xec {IN-HARDIRQ-W} state was registered at: [] mark_lock+0x19c/0x6a0 [] __lock_acquire+0xa2c/0x1d00 [] lock_acquire+0x58/0x7c [] _raw_spin_lock_irqsave+0x54/0x6c [] int_chnl_int_v2_hw+0x1c4/0x248 [] handle_irq_event_percpu+0x9c/0x144 [] handle_irq_event+0x44/0x74 [] handle_fasteoi_irq+0xb4/0x188 [] generic_handle_irq+0x24/0x38 [] __handle_domain_irq+0x60/0xac [] gic_handle_irq+0xcc/0x168 [] el1_irq+0x6c/0xe0 [] default_idle_call+0x1c/0x34 [] cpu_startup_entry+0x1d4/0x228 [] rest_init+0x150/0x160 [] start_kernel+0x3a4/0x3b8 [<00000000008bb000>] 0x8bb000 irq event stamp: 32661 hardirqs last enabled at (32661): [] __mutex_unlock_slowpath+0x108/0x18c hardirqs last disabled at (32660): [] __mutex_unlock_slowpath+0x44/0x18c softirqs last enabled at (25114): [] __do_softirq+0x210/0x27c softirqs last disabled at (25095): [] irq_exit+0x9c/0xe8 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&hisi_hba->lock)->rlock); lock(&(&hisi_hba->lock)->rlock); *** DEADLOCK *** 2 locks held by kworker/u64:1/168: #0: ("%s"shost->work_q_name){++++.+}, at: [] process_one_work+0x134/0x3cc #1: ((&sw->work)#2){+.+.+.}, at: [] process_one_work+0x134/0x3cc stack backtrace: CPU: 4 PID: 168 Comm: kworker/u64:1 Not tainted 4.4.8+ #12 Hardware name: Huawei Technologies Co., Ltd. D03/D03, BIOS 1.12 01/01/1900 Workqueue: scsi_wq_1 sas_discover_domain Call trace: [] dump_backtrace+0x0/0x114 [] show_stack+0x14/0x1c [] dump_stack+0xb4/0xf0 [] print_usage_bug+0x210/0x2b4 [] mark_lock+0x5fc/0x6a0 [] __lock_acquire+0x800/0x1d00 [] lock_acquire+0x58/0x7c [] _raw_spin_lock+0x44/0x58 [] alloc_dev_quirk_v2_hw+0x48/0xec [] hisi_sas_dev_found+0x48/0x1b8 [] sas_notify_lldd_dev_found+0x34/0xe0 [] sas_discover_root_expander+0x58/0x128 [] sas_discover_domain+0x4bc/0x564 [] process_one_work+0x1a0/0x3cc [] worker_thread+0x138/0x438 [] kthread+0xdc/0xf0 [] ret_from_fork+0x10/0x40 Signed-off-by: Wei Xu Signed-off-by: John Garry Reviewed-by: Zhangfei Gao Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 7d5edd1f4bba..f96560431cf1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1912,14 +1912,9 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct sas_ha_struct *sas_ha = &hisi_hba->sha; - unsigned long flags; hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); - - spin_lock_irqsave(&hisi_hba->lock, flags); sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_RX_BCST_ACK_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0); From cd4d37236590507cb96e1dee75fdc1ffac56ded3 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 31 May 2016 20:38:51 +0800 Subject: [PATCH 021/101] hisi_sas: update driver version to 1.5 Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index d7cab724f203..4731d3241323 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -23,7 +23,7 @@ #include #include -#define DRV_VERSION "v1.4" +#define DRV_VERSION "v1.5" #define HISI_SAS_MAX_PHYS 9 #define HISI_SAS_MAX_QUEUES 32 From 09d2a4e7fca62369b6ad018fb03ac8df96c93823 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 4 Jun 2016 20:14:30 +0100 Subject: [PATCH 022/101] bnx2i: fix spelling mistake "complection" -> "completion" Trivial fix to spelling mistake in printk message. Signed-off-by: Colin Ian King Reviewed-by: Laurence Oberman Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2i/bnx2i_hwi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index fb072cc5e9fd..42921dbba927 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -2417,7 +2417,7 @@ static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba, ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id); if (!ep) { printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending " - "offload request, unexpected complection\n"); + "offload request, unexpected completion\n"); return; } From 7e1ee4412ca35b17e21159d85224e37e8f259311 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 May 2016 10:57:31 -0700 Subject: [PATCH 023/101] scsi: ultrastor.c depends on ISA_DMA_API Fix build when CONFIG_ISA_DMA_API is not enabled. Fixes these build errors (on x86_64): ../drivers/scsi/ultrastor.c: In function 'ultrastor_14f_detect': ../drivers/scsi/ultrastor.c:519:5: error: implicit declaration of function 'request_dma' [-Werror=implicit-function-declaration] if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) { ^ ../drivers/scsi/ultrastor.c: In function 'ultrastor_release': ../drivers/scsi/ultrastor.c:658:3: error: implicit declaration of function 'free_dma' [-Werror=implicit-function-declaration] free_dma(shost->dma_channel); ^ Signed-off-by: Randy Dunlap Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 98e5d51a3346..1918f5483b23 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1433,7 +1433,7 @@ config SCSI_U14_34F_MAX_TAGS config SCSI_ULTRASTOR tristate "UltraStor SCSI support" - depends on X86 && ISA && SCSI + depends on X86 && ISA && SCSI && ISA_DMA_API ---help--- This is support for the UltraStor 14F, 24F and 34F SCSI-2 host adapter family. This driver is explained in section 3.12 of the From baa6719f902af9c03e528b08dfb847de295b5137 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 24 May 2016 08:11:58 +0200 Subject: [PATCH 024/101] libfc: Update rport reference counting Originally libfc would just be initializing the refcount to '1', and using the disc_mutex to synchronize if and when the final put should be happening. This has a race condition as the mutex might be delayed, causing other threads to access an invalid structure. This patch updates the rport reference counting to increase the reference every time 'rport_lookup' is called, and decreases the reference correspondingly. This removes the need to hold 'disc_mutex' when removing the structure, and avoids the above race condition. Signed-off-by: Hannes Reinecke Acked-by: Vasu Dev Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_ctlr.c | 7 +---- drivers/scsi/libfc/fc_lport.c | 19 +++++++++----- drivers/scsi/libfc/fc_rport.c | 49 ++++++++++++++++++----------------- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 3e83d485f743..ada4bdec9a4c 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2496,14 +2496,13 @@ static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac) struct fcoe_rport *frport; int ret = -1; - rcu_read_lock(); rdata = lport->tt.rport_lookup(lport, port_id); if (rdata) { frport = fcoe_ctlr_rport(rdata); memcpy(mac, frport->enode_mac, ETH_ALEN); ret = 0; + kref_put(&rdata->kref, lport->tt.rport_destroy); } - rcu_read_unlock(); return ret; } @@ -2585,11 +2584,7 @@ static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); return; } - mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, new->ids.port_id); - if (rdata) - kref_get(&rdata->kref); - mutex_unlock(&lport->disc.disc_mutex); if (rdata) { if (rdata->ids.node_name == new->ids.node_name && rdata->ids.port_name == new->ids.port_name) { diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e01a29863c38..b9b44daff159 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -2090,7 +2090,7 @@ int fc_lport_bsg_request(struct fc_bsg_job *job) struct fc_rport *rport; struct fc_rport_priv *rdata; int rc = -EINVAL; - u32 did; + u32 did, tov; job->reply->reply_payload_rcv_len = 0; if (rsp) @@ -2121,15 +2121,20 @@ int fc_lport_bsg_request(struct fc_bsg_job *job) case FC_BSG_HST_CT: did = ntoh24(job->request->rqst_data.h_ct.port_id); - if (did == FC_FID_DIR_SERV) + if (did == FC_FID_DIR_SERV) { rdata = lport->dns_rdata; - else + if (!rdata) + break; + tov = rdata->e_d_tov; + } else { rdata = lport->tt.rport_lookup(lport, did); + if (!rdata) + break; + tov = rdata->e_d_tov; + kref_put(&rdata->kref, lport->tt.rport_destroy); + } - if (!rdata) - break; - - rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov); + rc = fc_lport_ct_request(job, lport, did, tov); break; case FC_BSG_HST_ELS_NOLOGIN: diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 589ff9aedd31..93f596182145 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -95,17 +95,23 @@ static const char *fc_rport_state_names[] = { * @lport: The local port to lookup the remote port on * @port_id: The remote port ID to look up * - * The caller must hold either disc_mutex or rcu_read_lock(). + * The reference count of the fc_rport_priv structure is + * increased by one. */ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, u32 port_id) { - struct fc_rport_priv *rdata; + struct fc_rport_priv *rdata = NULL, *tmp_rdata; - list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) - if (rdata->ids.port_id == port_id) - return rdata; - return NULL; + rcu_read_lock(); + list_for_each_entry_rcu(tmp_rdata, &lport->disc.rports, peers) + if (tmp_rdata->ids.port_id == port_id && + kref_get_unless_zero(&tmp_rdata->kref)) { + rdata = tmp_rdata; + break; + } + rcu_read_unlock(); + return rdata; } /** @@ -340,7 +346,6 @@ static void fc_rport_work(struct work_struct *work) fc_remote_port_delete(rport); } - mutex_lock(&lport->disc.disc_mutex); mutex_lock(&rdata->rp_mutex); if (rdata->rp_state == RPORT_ST_DELETE) { if (port_id == FC_FID_DIR_SERV) { @@ -370,7 +375,6 @@ static void fc_rport_work(struct work_struct *work) fc_rport_enter_ready(rdata); mutex_unlock(&rdata->rp_mutex); } - mutex_unlock(&lport->disc.disc_mutex); break; default: @@ -702,7 +706,7 @@ out: err: mutex_unlock(&rdata->rp_mutex); put: - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); + kref_put(&rdata->kref, lport->tt.rport_destroy); return; bad: FC_RPORT_DBG(rdata, "Bad FLOGI response\n"); @@ -762,8 +766,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); disc = &lport->disc; - mutex_lock(&disc->disc_mutex); - if (!lport->point_to_multipoint) { rjt_data.reason = ELS_RJT_UNSUP; rjt_data.explan = ELS_EXPL_NONE; @@ -808,7 +810,7 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_FIP; rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; - goto reject; + goto reject_put; case RPORT_ST_FLOGI: case RPORT_ST_PLOGI_WAIT: case RPORT_ST_PLOGI: @@ -825,13 +827,13 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_BUSY; rjt_data.explan = ELS_EXPL_NONE; - goto reject; + goto reject_put; } if (fc_rport_login_complete(rdata, fp)) { mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; - goto reject; + goto reject_put; } fp = fc_frame_alloc(lport, sizeof(*flp)); @@ -851,12 +853,13 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); out: mutex_unlock(&rdata->rp_mutex); - mutex_unlock(&disc->disc_mutex); + kref_put(&rdata->kref, lport->tt.rport_destroy); fc_frame_free(rx_fp); return; +reject_put: + kref_put(&rdata->kref, lport->tt.rport_destroy); reject: - mutex_unlock(&disc->disc_mutex); lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); fc_frame_free(rx_fp); } @@ -923,7 +926,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); + kref_put(&rdata->kref, lport->tt.rport_destroy); } static bool @@ -1477,14 +1480,11 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) struct fc_rport_priv *rdata; struct fc_seq_els_data els_data; - mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp)); - if (!rdata) { - mutex_unlock(&lport->disc.disc_mutex); + if (!rdata) goto reject; - } + mutex_lock(&rdata->rp_mutex); - mutex_unlock(&lport->disc.disc_mutex); switch (rdata->rp_state) { case RPORT_ST_PRLI: @@ -1494,6 +1494,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) break; default: mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, lport->tt.rport_destroy); goto reject; } @@ -1524,6 +1525,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) } mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); return; reject: @@ -1907,7 +1909,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) sid = fc_frame_sid(fp); - mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, sid); if (rdata) { mutex_lock(&rdata->rp_mutex); @@ -1916,10 +1917,10 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) fc_rport_enter_delete(rdata, RPORT_EV_LOGO); mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else FC_RPORT_ID_DBG(lport, sid, "Received LOGO from non-logged-in port\n"); - mutex_unlock(&lport->disc.disc_mutex); fc_frame_free(fp); } From fb0cc8d1c1881c56683123ff129452e88fdf5575 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Tue, 31 May 2016 17:15:07 -0400 Subject: [PATCH 025/101] scsi_debug: fix sleep in invalid context In this post: http://www.spinics.net/lists/linux-scsi/msg97124.html the author shows some kernel infrastructure complaining about a sleep in an invalid context. Remove offending call to vmalloc(). Instead of using kzalloc() which reviewers didn't like, use a bucket system (64 bytes on the stack) and potentially multiple calls to sg_pcopy_from_buffer() to construct the 'data-in' buffer for the SCSI REPORT LUNS command. Signed-off-by: Douglas Gilbert Acked-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 93 +++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 0f9ba41e27d8..6a219a0844d3 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -890,7 +890,7 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return 0; } -/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ +/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, int arr_len) { @@ -909,7 +909,35 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, return 0; } -/* Returns number of bytes fetched into 'arr' or -1 if error. */ +/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else + * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple + * calls, not required to write in ascending offset order. Assumes resid + * set to scsi_bufflen() prior to any calls. + */ +static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, + int arr_len, unsigned int off_dst) +{ + int act_len, n; + struct scsi_data_buffer *sdb = scsi_in(scp); + off_t skip = off_dst; + + if (sdb->length <= off_dst) + return 0; + if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) + return DID_ERROR << 16; + + act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, + arr, arr_len, skip); + pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", + __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid); + n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len); + sdb->resid = min(sdb->resid, n); + return 0; +} + +/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into + * 'arr' or -1 if error. + */ static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, int arr_len) { @@ -3269,6 +3297,8 @@ static int resp_get_lba_status(struct scsi_cmnd *scp, return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); } +#define RL_BUCKET_ELEMS 8 + /* Even though each pseudo target has a REPORT LUNS "well known logical unit" * (W-LUN), the normal Linux scanning logic does not associate it with a * device (e.g. /dev/sg7). The following magic will make that association: @@ -3285,12 +3315,14 @@ static int resp_report_luns(struct scsi_cmnd *scp, unsigned char select_report; u64 lun; struct scsi_lun *lun_p; - u8 *arr; + u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; unsigned int lun_cnt; /* normal LUN count (max: 256) */ unsigned int wlun_cnt; /* report luns W-LUN count */ unsigned int tlun_cnt; /* total LUN count */ unsigned int rlen; /* response length (in bytes) */ - int i, res; + int k, j, n, res; + unsigned int off_rsp = 0; + const int sz_lun = sizeof(struct scsi_lun); clear_luns_changed_on_target(devip); @@ -3329,33 +3361,40 @@ static int resp_report_luns(struct scsi_cmnd *scp, --lun_cnt; tlun_cnt = lun_cnt + wlun_cnt; - - rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8; - arr = vmalloc(rlen); - if (!arr) { - mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, - INSUFF_RES_ASCQ); - return check_condition_result; - } - memset(arr, 0, rlen); + rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ + scsi_set_resid(scp, scsi_bufflen(scp)); pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); - /* luns start at byte 8 in response following the header */ - lun_p = (struct scsi_lun *)&arr[8]; - - /* LUNs use single level peripheral device addressing method */ + /* loops rely on sizeof response header same as sizeof lun (both 8) */ lun = sdebug_no_lun_0 ? 1 : 0; - for (i = 0; i < lun_cnt; i++) - int_to_scsilun(lun++, lun_p++); - - if (wlun_cnt) - int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++); - - put_unaligned_be32(rlen - 8, &arr[0]); - - res = fill_from_dev_buffer(scp, arr, rlen); - vfree(arr); + for (k = 0, j = 0, res = 0; true; ++k, j = 0) { + memset(arr, 0, sizeof(arr)); + lun_p = (struct scsi_lun *)&arr[0]; + if (k == 0) { + put_unaligned_be32(rlen, &arr[0]); + ++lun_p; + j = 1; + } + for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { + if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) + break; + int_to_scsilun(lun++, lun_p); + } + if (j < RL_BUCKET_ELEMS) + break; + n = j * sz_lun; + res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); + if (res) + return res; + off_rsp += n; + } + if (wlun_cnt) { + int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); + ++j; + } + if (j > 0) + res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); return res; } From 2a81ffdd9da1dc122c195cd53a0c1605f29c10d0 Mon Sep 17 00:00:00 2001 From: Dave Carroll Date: Wed, 15 Jun 2016 11:27:17 -0600 Subject: [PATCH 026/101] MAINTAINERS: Update email address for aacraid Update the email address for aacraid from Adaptec to Microsemi. Signed-off-by: Dave Carroll Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ee90806ff1c3..104f943aa3a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -213,7 +213,7 @@ S: Maintained F: drivers/media/dvb-frontends/a8293* AACRAID SCSI RAID DRIVER -M: Adaptec OEM Raid Solutions +M: Adaptec OEM Raid Solutions L: linux-scsi@vger.kernel.org W: http://www.adaptec.com/ S: Supported From f411396d9492761ab4f9fb58aa363a2926b94af8 Mon Sep 17 00:00:00 2001 From: "Manoj N. Kumar" Date: Wed, 15 Jun 2016 18:49:20 -0500 Subject: [PATCH 027/101] cxlflash: Fix to drain operations from previous reset While running 'sg_reset -H' in a loop with a user-space application active, hit the following exception: cpu 0x2: Vector: 300 (Data Access) pc: : afu_attach+0x50/0x240 [cxlflash] lr: : cxlflash_afu_recover+0x3dc/0x7d0 [cxlflash] pid = 20365, comm = run_block_fvt Linux version 4.5.0-491-26f710d+ cxlflash_afu_recover+0x3dc/0x7d0 [cxlflash] cxlflash_ioctl+0x5a8/0x6f0 [cxlflash] scsi_ioctl+0x3b0/0x4c0 sd_ioctl+0x110/0x190 blkdev_ioctl+0x28c/0xc20 block_ioctl+0xa4/0xd0 do_vfs_ioctl+0xd8/0x8c0 SyS_ioctl+0xd4/0xf0 system_call+0x38/0xb4 The problem here is that the problem space area is unmapped while the application issues the DK_CXLFLASH_RECOVER_AFU ioctl. This is the order I observe: proc1 proc2 1) sg_reset 2) ioctl(DK_CXLFLASH_RECOVER_AFU) 3) sg_reset again causing a PSA unmap 4) continues RECOVER_AFU processing The resolution to this problem is to have the reset handler drain all outstanding user space initiated ioctls before proceeding. It is safe to drain after the state has been changed to STATE_RESET. Also since drain_ioctls() was static, it had to be moved up a bit to be before cxlflash_eh_host_reset_handler(). Signed-off-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 8fb9643fe6e3..f1f977f83e17 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1915,6 +1915,19 @@ static int afu_reset(struct cxlflash_cfg *cfg) return rc; } +/** + * drain_ioctls() - wait until all currently executing ioctls have completed + * @cfg: Internal structure associated with the host. + * + * Obtain write access to read/write semaphore that wraps ioctl + * handling to 'drain' ioctls currently executing. + */ +static void drain_ioctls(struct cxlflash_cfg *cfg) +{ + down_write(&cfg->ioctl_rwsem); + up_write(&cfg->ioctl_rwsem); +} + /** * cxlflash_eh_device_reset_handler() - reset a single LUN * @scp: SCSI command to send. @@ -1986,6 +1999,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) switch (cfg->state) { case STATE_NORMAL: cfg->state = STATE_RESET; + drain_ioctls(cfg); cxlflash_mark_contexts_error(cfg); rcr = afu_reset(cfg); if (rcr) { @@ -2503,19 +2517,6 @@ out_remove: goto out; } -/** - * drain_ioctls() - wait until all currently executing ioctls have completed - * @cfg: Internal structure associated with the host. - * - * Obtain write access to read/write semaphore that wraps ioctl - * handling to 'drain' ioctls currently executing. - */ -static void drain_ioctls(struct cxlflash_cfg *cfg) -{ - down_write(&cfg->ioctl_rwsem); - up_write(&cfg->ioctl_rwsem); -} - /** * cxlflash_pci_error_detected() - called when a PCI error is detected * @pdev: PCI device struct. From 96e1b660faa44c958d19ccf064b939a00bed6c90 Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Wed, 15 Jun 2016 18:49:38 -0500 Subject: [PATCH 028/101] cxlflash: Add device dependent flags Device dependent flags are needed to support functions that are specific to a particular device. One such case is - some CXL Flash cards need to be notified of device shutdown. For other CXL devices, this feature does not prove to be useful yet. Such distinct features need to be identified in the driver to bypass or invoke specific functionality. In this patch, a member 'flags' has been added to device dependent values. These flags will be used and expanded in the future to support various device specific functions. Signed-off-by: Uma Krishnan Acked-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 6 ++++-- drivers/scsi/cxlflash/main.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index f1f977f83e17..e027fa0fe430 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2333,8 +2333,10 @@ static struct scsi_host_template driver_template = { /* * Device dependent values */ -static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; -static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS }; +static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, + 0ULL }; +static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, + 0ULL }; /* * PCI device binding table diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index eb9d8f730b38..029f51743a24 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -88,6 +88,7 @@ enum undo_level { struct dev_dependent_vals { u64 max_sectors; + u64 flags; }; struct asyc_intr_info { From 704c4b0ddc03fc8a6575086070a823d3ef6e5fc4 Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Wed, 15 Jun 2016 18:49:57 -0500 Subject: [PATCH 029/101] cxlflash: Shutdown notify support for CXL Flash cards Some CXL Flash cards need notification of device shutdown in order to flush pending I/Os. A PCI notification hook for shutdown has been added where the driver notifies the card and returns. When the device is removed in the PCI remove path, notification code will wait for shutdown processing to complete. Signed-off-by: Uma Krishnan Acked-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 67 ++++++++++++++++++++++++++++++++- drivers/scsi/cxlflash/main.h | 1 + drivers/scsi/cxlflash/sislite.h | 6 +++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index e027fa0fe430..860008d42466 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -764,6 +764,67 @@ static void term_afu(struct cxlflash_cfg *cfg) pr_debug("%s: returning\n", __func__); } +/** + * notify_shutdown() - notifies device of pending shutdown + * @cfg: Internal structure associated with the host. + * @wait: Whether to wait for shutdown processing to complete. + * + * This function will notify the AFU that the adapter is being shutdown + * and will wait for shutdown processing to complete if wait is true. + * This notification should flush pending I/Os to the device and halt + * further I/Os until the next AFU reset is issued and device restarted. + */ +static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + struct sisl_global_map __iomem *global = &afu->afu_map->global; + struct dev_dependent_vals *ddv; + u64 reg, status; + int i, retry_cnt = 0; + + ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data; + if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN)) + return; + + /* Notify AFU */ + for (i = 0; i < NUM_FC_PORTS; i++) { + reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]); + reg |= SISL_FC_SHUTDOWN_NORMAL; + writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]); + } + + if (!wait) + return; + + /* Wait up to 1.5 seconds for shutdown processing to complete */ + for (i = 0; i < NUM_FC_PORTS; i++) { + retry_cnt = 0; + while (true) { + status = readq_be(&global->fc_regs[i][FC_STATUS / 8]); + if (status & SISL_STATUS_SHUTDOWN_COMPLETE) + break; + if (++retry_cnt >= MC_RETRY_CNT) { + dev_dbg(dev, "%s: port %d shutdown processing " + "not yet completed\n", __func__, i); + break; + } + msleep(100 * retry_cnt); + } + } +} + +/** + * cxlflash_shutdown() - shutdown handler + * @pdev: PCI device associated with the host. + */ +static void cxlflash_shutdown(struct pci_dev *pdev) +{ + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + + notify_shutdown(cfg, false); +} + /** * cxlflash_remove() - PCI entry point to tear down host * @pdev: PCI device associated with the host. @@ -785,6 +846,9 @@ static void cxlflash_remove(struct pci_dev *pdev) cfg->tmf_slock); spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); + /* Notify AFU and wait for shutdown processing to complete */ + notify_shutdown(cfg, true); + cfg->state = STATE_FAILTERM; cxlflash_stop_term_user_contexts(cfg); @@ -2336,7 +2400,7 @@ static struct scsi_host_template driver_template = { static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, 0ULL }; static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, - 0ULL }; + CXLFLASH_NOTIFY_SHUTDOWN }; /* * PCI device binding table @@ -2613,6 +2677,7 @@ static struct pci_driver cxlflash_driver = { .id_table = cxlflash_pci_table, .probe = cxlflash_probe, .remove = cxlflash_remove, + .shutdown = cxlflash_shutdown, .err_handler = &cxlflash_err_handler, }; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 029f51743a24..f54bbd5a6062 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -89,6 +89,7 @@ enum undo_level { struct dev_dependent_vals { u64 max_sectors; u64 flags; +#define CXLFLASH_NOTIFY_SHUTDOWN 0x0000000000000001ULL }; struct asyc_intr_info { diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 0b3366f5e6f6..347fc1671975 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -311,6 +311,12 @@ struct sisl_global_regs { #define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) #define SISL_FC_INTERNAL_SHIFT 32 +#define SISL_FC_SHUTDOWN_NORMAL 0x0000000000000010ULL +#define SISL_FC_SHUTDOWN_ABRUPT 0x0000000000000020ULL + +#define SISL_STATUS_SHUTDOWN_ACTIVE 0x0000000000000010ULL +#define SISL_STATUS_SHUTDOWN_COMPLETE 0x0000000000000020ULL + #define SISL_ASTATUS_UNMASK 0xFFFFULL /* 1 means unmasked */ #define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ From 29374ec6e2160290e758a3cac1d2d81dd9613f4a Mon Sep 17 00:00:00 2001 From: Jim Gill Date: Mon, 20 Jun 2016 21:58:28 -0400 Subject: [PATCH 030/101] vmw_pvscsi: Change to update maintainer details (name, email) [mkp: Updated MAINTAINERS] Signed-off-by: Jim Gill Acked-by: Arvind Kumar Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- drivers/scsi/vmw_pvscsi.c | 2 +- drivers/scsi/vmw_pvscsi.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 104f943aa3a3..87fe356f5d94 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12302,7 +12302,7 @@ S: Maintained F: drivers/net/vmxnet3/ VMware PVSCSI driver -M: Arvind Kumar +M: Jim Gill M: VMware PV-Drivers L: linux-scsi@vger.kernel.org S: Maintained diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 6164634aff18..4a0d3cdc607c 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Maintained by: Arvind Kumar + * Maintained by: Jim Gill * */ diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h index 12712c92f37a..c097d2ccbde3 100644 --- a/drivers/scsi/vmw_pvscsi.h +++ b/drivers/scsi/vmw_pvscsi.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Maintained by: Arvind Kumar + * Maintained by: Jim Gill * */ From 0da21c4417ce8fac70bb46dd58c3a63f64bad76c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 10 Jun 2016 22:39:45 +0200 Subject: [PATCH 031/101] 53c700: Use proper debug printk format specifiers When enabling the debug options NCR_700_DEBUG and NCR_700_TAG_DEBUG various printk format warnings can be seen like: drivers/scsi/53c700.c:357:2: warning: format %p expects argument of type void * , but argument 4 has type dma_addr_t [-Wformat=] script_patch_32(hostdata->dev, script, MessageLocation, Fix them by using the right printk format specifiers. Signed-off-by: Helge Deller Signed-off-by: Martin K. Petersen --- drivers/scsi/53c700.c | 2 +- drivers/scsi/53c700.h | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 3ddc85e6efd6..55562019acf8 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -1892,7 +1892,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); slot->SG[i].pAddr = 0; dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE); - DEBUG((" SETTING %08lx to %x\n", + DEBUG((" SETTING %p to %x\n", (&slot->pSG[i].ins), slot->SG[i].ins)); } diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index e06bdfeab420..c893a5d3ff8d 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -423,23 +423,25 @@ struct NCR_700_Host_Parameters { #define script_patch_32(dev, script, symbol, value) \ { \ int i; \ + dma_addr_t da = value; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \ + __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + da; \ (script)[A_##symbol##_used[i]] = bS_to_host(val); \ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching %s at %d to 0x%lx\n", \ - #symbol, A_##symbol##_used[i], (value))); \ + DEBUG((" script, patching %s at %d to %pad\n", \ + #symbol, A_##symbol##_used[i], &da)); \ } \ } #define script_patch_32_abs(dev, script, symbol, value) \ { \ int i; \ + dma_addr_t da = value; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - (script)[A_##symbol##_used[i]] = bS_to_host(value); \ + (script)[A_##symbol##_used[i]] = bS_to_host(da); \ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching %s at %d to 0x%lx\n", \ - #symbol, A_##symbol##_used[i], (value))); \ + DEBUG((" script, patching %s at %d to %pad\n", \ + #symbol, A_##symbol##_used[i], &da)); \ } \ } From 540eb1eef0aba8bd10b7ebb3dc56cdb9e480164f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 17:47:25 +0200 Subject: [PATCH 032/101] scsi: libfc: fix seconds_since_last_reset calculation The fc_get_host_stats() function contains a complex conversion from jiffies to timespec to seconds. As we try to get rid of uses of struct timespec, we can clean this up and replace it with a simpler computation. Simply dividing the difference in jiffies by HZ is not only much more efficient, it also avoids a problem that causes the seconds_since_last_reset value to be incorrect if jiffies has overrun since the 'boot_time' value was recorded. Signed-off-by: Arnd Bergmann Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_lport.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index b9b44daff159..04ce7cfb6d1b 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -301,7 +301,6 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) { struct fc_host_statistics *fc_stats; struct fc_lport *lport = shost_priv(shost); - struct timespec v0, v1; unsigned int cpu; u64 fcp_in_bytes = 0; u64 fcp_out_bytes = 0; @@ -309,9 +308,7 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) fc_stats = &lport->host_stats; memset(fc_stats, 0, sizeof(struct fc_host_statistics)); - jiffies_to_timespec(jiffies, &v0); - jiffies_to_timespec(lport->boot_time, &v1); - fc_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); + fc_stats->seconds_since_last_reset = (lport->boot_time - jiffies) / HZ; for_each_possible_cpu(cpu) { struct fc_stats *stats; From 40e4c0a4e1d5414ed33e5bc846a832dc868fa65d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 21 Jun 2016 11:02:39 +0200 Subject: [PATCH 033/101] scsi: wd7000: print sector number as 64-bit Enabling format checking in dprintk() shows that wd7000_biosparam uses an incorrect format string for sector_t: drivers/scsi/wd7000.c: In function 'wd7000_biosparam': drivers/scsi/wd7000.c:1594:21: error: format '%d' expects argument of type 'int', but argument 3 has type 'sector_t {aka long long unsigned int}' [-Werror=format=] As sector_t can be 32-bit wide, this adds a cast to 'u64' and prints that with the correct format. The change to use no_printk() generally helps with finding this kind of hidden format string bug, and I found that when building with "-Wextra", which warned about an empty else clause in } else dprintk("ok!\n"); Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/scsi/wd7000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 0c0f17b9a3eb..409f959845c4 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -192,7 +192,7 @@ #ifdef WD7000_DEBUG #define dprintk printk #else -#define dprintk(format,args...) +#define dprintk no_printk #endif /* @@ -1591,8 +1591,8 @@ static int wd7000_biosparam(struct scsi_device *sdev, { char b[BDEVNAME_SIZE]; - dprintk("wd7000_biosparam: dev=%s, size=%d, ", - bdevname(bdev, b), capacity); + dprintk("wd7000_biosparam: dev=%s, size=%llu, ", + bdevname(bdev, b), (u64)capacity); (void)b; /* unused var warning? */ /* From 2a6a20ea7d894464ca6bd402058c1aadf796a48c Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 23 Jun 2016 14:37:20 +0200 Subject: [PATCH 034/101] snic: Fix use-after-free in case of a dma mapping error If there is a dma mapping error snic kfree()s buf right before printing it. Change the order to not accidently trip on memory that's not owned by us anymore. Signed-off-by: Johannes Thumshirn Acked-by: Narsimhulu Musini Reviewed-by: Laurence Oberman Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_disc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index b0fefd67cac3..b106596cc0cf 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -113,11 +113,11 @@ snic_queue_report_tgt_req(struct snic *snic) pa = pci_map_single(snic->pdev, buf, buf_len, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(snic->pdev, pa)) { - kfree(buf); - snic_req_free(snic, rqi); SNIC_HOST_ERR(snic->shost, "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n", buf); + kfree(buf); + snic_req_free(snic, rqi); ret = -EINVAL; goto error; From 49a75815e996a8719463090d9666bd120d9bae91 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 23 Jun 2016 10:22:28 +0200 Subject: [PATCH 035/101] MAINTAINERS: Change FCoE maintainer Vasu is going to resign from his maintainer role and I'll take over. Signed-off-by: Johannes Thumshirn Acked-by: Vasu Dev Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 87fe356f5d94..c791298723d2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4665,7 +4665,7 @@ S: Maintained F: drivers/staging/fbtft/ FCOE SUBSYSTEM (libfc, libfcoe, fcoe) -M: Vasu Dev +M: Johannes Thumshirn L: fcoe-devel@open-fcoe.org W: www.Open-FCoE.org S: Supported From 4b9bc86d5a999e344098303882d6395d39e36c13 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 12 Apr 2016 17:16:54 +0200 Subject: [PATCH 036/101] fcoe: convert to kworker The driver creates its own per-CPU threads which are updated based on CPU hotplug events. It is also possible to use kworkers and remove some of the kthread infrastrucure. The code checked ->thread to decide if there is an active per-CPU thread. By using the kworker infrastructure this is no longer possible (or required). The thread pointer is saved in `kthread' instead of `thread' so anything trying to use thread is caught by the compiler. Currently only the bnx2fc driver is using struct fcoe_percpu_s and the kthread member. After a CPU went offline, we may still enqueue items on the "offline" CPU. This isn't much of a problem. The work will be done on a random CPU. The allocated crc_eof_page page won't be cleaned up. It is probably expected that the CPU comes up at some point so it should not be a problem. The crc_eof_page memory is released of course once the module is removed. This patch was only compile-tested due to -ENODEV. Cc: Vasu Dev Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: fcoe-devel@open-fcoe.org Cc: linux-scsi@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Tested-by: Johannes Thumshirn Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 8 +- drivers/scsi/fcoe/fcoe.c | 276 +++--------------------------- include/scsi/libfcoe.h | 6 +- 3 files changed, 34 insertions(+), 256 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index a1881993982c..d6800afd0232 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -486,7 +486,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, __skb_queue_tail(&bg->fcoe_rx_list, skb); if (bg->fcoe_rx_list.qlen == 1) - wake_up_process(bg->thread); + wake_up_process(bg->kthread); spin_unlock(&bg->fcoe_rx_list.lock); @@ -2715,7 +2715,7 @@ static int __init bnx2fc_mod_init(void) } wake_up_process(l2_thread); spin_lock_bh(&bg->fcoe_rx_list.lock); - bg->thread = l2_thread; + bg->kthread = l2_thread; spin_unlock_bh(&bg->fcoe_rx_list.lock); for_each_possible_cpu(cpu) { @@ -2788,8 +2788,8 @@ static void __exit bnx2fc_mod_exit(void) /* Destroy global thread */ bg = &bnx2fc_global; spin_lock_bh(&bg->fcoe_rx_list.lock); - l2_thread = bg->thread; - bg->thread = NULL; + l2_thread = bg->kthread; + bg->kthread = NULL; while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) kfree_skb(skb); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 0efe7112fc1f..f7c7ccc156da 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -67,9 +67,6 @@ static DEFINE_MUTEX(fcoe_config_mutex); static struct workqueue_struct *fcoe_wq; -/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ -static DECLARE_COMPLETION(fcoe_flush_completion); - /* fcoe host list */ /* must only by accessed under the RTNL mutex */ static LIST_HEAD(fcoe_hostlist); @@ -80,7 +77,6 @@ static int fcoe_reset(struct Scsi_Host *); static int fcoe_xmit(struct fc_lport *, struct fc_frame *); static int fcoe_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); -static int fcoe_percpu_receive_thread(void *); static void fcoe_percpu_clean(struct fc_lport *); static int fcoe_link_ok(struct fc_lport *); @@ -107,7 +103,6 @@ static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, static int fcoe_ddp_done(struct fc_lport *, u16); static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, unsigned int); -static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); static int fcoe_dcb_app_notification(struct notifier_block *notifier, ulong event, void *ptr); @@ -136,11 +131,6 @@ static struct notifier_block fcoe_notifier = { .notifier_call = fcoe_device_notification, }; -/* notification function for CPU hotplug events */ -static struct notifier_block fcoe_cpu_notifier = { - .notifier_call = fcoe_cpu_callback, -}; - /* notification function for DCB events */ static struct notifier_block dcb_notifier = { .notifier_call = fcoe_dcb_app_notification, @@ -1245,152 +1235,21 @@ static int __exit fcoe_if_exit(void) return 0; } -/** - * fcoe_percpu_thread_create() - Create a receive thread for an online CPU - * @cpu: The CPU index of the CPU to create a receive thread for - */ -static void fcoe_percpu_thread_create(unsigned int cpu) +static void fcoe_thread_cleanup_local(unsigned int cpu) { - struct fcoe_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(fcoe_percpu, cpu); - - thread = kthread_create_on_node(fcoe_percpu_receive_thread, - (void *)p, cpu_to_node(cpu), - "fcoethread/%d", cpu); - - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - wake_up_process(thread); - - spin_lock_bh(&p->fcoe_rx_list.lock); - p->thread = thread; - spin_unlock_bh(&p->fcoe_rx_list.lock); - } -} - -/** - * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU - * @cpu: The CPU index of the CPU whose receive thread is to be destroyed - * - * Destroys a per-CPU Rx thread. Any pending skbs are moved to the - * current CPU's Rx thread. If the thread being destroyed is bound to - * the CPU processing this context the skbs will be freed. - */ -static void fcoe_percpu_thread_destroy(unsigned int cpu) -{ - struct fcoe_percpu_s *p; - struct task_struct *thread; struct page *crc_eof; - struct sk_buff *skb; -#ifdef CONFIG_SMP - struct fcoe_percpu_s *p0; - unsigned targ_cpu = get_cpu(); -#endif /* CONFIG_SMP */ + struct fcoe_percpu_s *p; - FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); - - /* Prevent any new skbs from being queued for this CPU. */ - p = &per_cpu(fcoe_percpu, cpu); + p = per_cpu_ptr(&fcoe_percpu, cpu); spin_lock_bh(&p->fcoe_rx_list.lock); - thread = p->thread; - p->thread = NULL; crc_eof = p->crc_eof_page; p->crc_eof_page = NULL; p->crc_eof_offset = 0; spin_unlock_bh(&p->fcoe_rx_list.lock); -#ifdef CONFIG_SMP - /* - * Don't bother moving the skb's if this context is running - * on the same CPU that is having its thread destroyed. This - * can easily happen when the module is removed. - */ - if (cpu != targ_cpu) { - p0 = &per_cpu(fcoe_percpu, targ_cpu); - spin_lock_bh(&p0->fcoe_rx_list.lock); - if (p0->thread) { - FCOE_DBG("Moving frames from CPU %d to CPU %d\n", - cpu, targ_cpu); - - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - __skb_queue_tail(&p0->fcoe_rx_list, skb); - spin_unlock_bh(&p0->fcoe_rx_list.lock); - } else { - /* - * The targeted CPU is not initialized and cannot accept - * new skbs. Unlock the targeted CPU and drop the skbs - * on the CPU that is going offline. - */ - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p0->fcoe_rx_list.lock); - } - } else { - /* - * This scenario occurs when the module is being removed - * and all threads are being destroyed. skbs will continue - * to be shifted from the CPU thread that is being removed - * to the CPU thread associated with the CPU that is processing - * the module removal. Once there is only one CPU Rx thread it - * will reach this case and we will drop all skbs and later - * stop the thread. - */ - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p->fcoe_rx_list.lock); - } - put_cpu(); -#else - /* - * This a non-SMP scenario where the singular Rx thread is - * being removed. Free all skbs and stop the thread. - */ - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p->fcoe_rx_list.lock); -#endif - - if (thread) - kthread_stop(thread); - if (crc_eof) put_page(crc_eof); -} - -/** - * fcoe_cpu_callback() - Handler for CPU hotplug events - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for fcoe - * - * Returns NOTIFY_OK always. - */ -static int fcoe_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); - fcoe_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); - fcoe_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; + flush_work(&p->work); } /** @@ -1509,26 +1368,6 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, fps = &per_cpu(fcoe_percpu, cpu); spin_lock(&fps->fcoe_rx_list.lock); - if (unlikely(!fps->thread)) { - /* - * The targeted CPU is not ready, let's target - * the first CPU now. For non-SMP systems this - * will check the same CPU twice. - */ - FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread " - "ready for incoming skb- using first online " - "CPU.\n"); - - spin_unlock(&fps->fcoe_rx_list.lock); - cpu = cpumask_first(cpu_online_mask); - fps = &per_cpu(fcoe_percpu, cpu); - spin_lock(&fps->fcoe_rx_list.lock); - if (!fps->thread) { - spin_unlock(&fps->fcoe_rx_list.lock); - goto err; - } - } - /* * We now have a valid CPU that we're targeting for * this skb. We also have this receive thread locked, @@ -1543,8 +1382,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, * in softirq context. */ __skb_queue_tail(&fps->fcoe_rx_list, skb); - if (fps->thread->state == TASK_INTERRUPTIBLE) - wake_up_process(fps->thread); + schedule_work_on(cpu, &fps->work); spin_unlock(&fps->fcoe_rx_list.lock); return NET_RX_SUCCESS; @@ -1712,15 +1550,6 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) return 0; } -/** - * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion - * @skb: The completed skb (argument required by destructor) - */ -static void fcoe_percpu_flush_done(struct sk_buff *skb) -{ - complete(&fcoe_flush_completion); -} - /** * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC * @lport: The local port the frame was received on @@ -1792,8 +1621,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) fr = fcoe_dev_from_skb(skb); lport = fr->fr_dev; if (unlikely(!lport)) { - if (skb->destructor != fcoe_percpu_flush_done) - FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n"); + FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n"); kfree_skb(skb); return; } @@ -1857,40 +1685,28 @@ drop: } /** - * fcoe_percpu_receive_thread() - The per-CPU packet receive thread - * @arg: The per-CPU context + * fcoe_receive_work() - The per-CPU worker + * @work: The work struct * - * Return: 0 for success */ -static int fcoe_percpu_receive_thread(void *arg) +static void fcoe_receive_work(struct work_struct *work) { - struct fcoe_percpu_s *p = arg; + struct fcoe_percpu_s *p; struct sk_buff *skb; struct sk_buff_head tmp; + p = container_of(work, struct fcoe_percpu_s, work); skb_queue_head_init(&tmp); - set_user_nice(current, MIN_NICE); + spin_lock_bh(&p->fcoe_rx_list.lock); + skb_queue_splice_init(&p->fcoe_rx_list, &tmp); + spin_unlock_bh(&p->fcoe_rx_list.lock); - while (!kthread_should_stop()) { + if (!skb_queue_len(&tmp)) + return; - spin_lock_bh(&p->fcoe_rx_list.lock); - skb_queue_splice_init(&p->fcoe_rx_list, &tmp); - - if (!skb_queue_len(&tmp)) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->fcoe_rx_list.lock); - schedule(); - continue; - } - - spin_unlock_bh(&p->fcoe_rx_list.lock); - - while ((skb = __skb_dequeue(&tmp)) != NULL) - fcoe_recv_frame(skb); - - } - return 0; + while ((skb = __skb_dequeue(&tmp))) + fcoe_recv_frame(skb); } /** @@ -2450,36 +2266,19 @@ static int fcoe_link_ok(struct fc_lport *lport) * * Must be called with fcoe_create_mutex held to single-thread completion. * - * This flushes the pending skbs by adding a new skb to each queue and - * waiting until they are all freed. This assures us that not only are - * there no packets that will be handled by the lport, but also that any - * threads already handling packet have returned. + * This flushes the pending skbs by flush the work item for each CPU. The work + * item on each possible CPU is flushed because we may have used the per-CPU + * struct of an offline CPU. */ static void fcoe_percpu_clean(struct fc_lport *lport) { struct fcoe_percpu_s *pp; - struct sk_buff *skb; unsigned int cpu; for_each_possible_cpu(cpu) { pp = &per_cpu(fcoe_percpu, cpu); - if (!pp->thread || !cpu_online(cpu)) - continue; - - skb = dev_alloc_skb(0); - if (!skb) - continue; - - skb->destructor = fcoe_percpu_flush_done; - - spin_lock_bh(&pp->fcoe_rx_list.lock); - __skb_queue_tail(&pp->fcoe_rx_list, skb); - if (pp->fcoe_rx_list.qlen == 1) - wake_up_process(pp->thread); - spin_unlock_bh(&pp->fcoe_rx_list.lock); - - wait_for_completion(&fcoe_flush_completion); + flush_work(&pp->work); } } @@ -2625,22 +2424,11 @@ static int __init fcoe_init(void) mutex_lock(&fcoe_config_mutex); for_each_possible_cpu(cpu) { - p = &per_cpu(fcoe_percpu, cpu); + p = per_cpu_ptr(&fcoe_percpu, cpu); + INIT_WORK(&p->work, fcoe_receive_work); skb_queue_head_init(&p->fcoe_rx_list); } - cpu_notifier_register_begin(); - - for_each_online_cpu(cpu) - fcoe_percpu_thread_create(cpu); - - /* Initialize per CPU interrupt thread */ - rc = __register_hotcpu_notifier(&fcoe_cpu_notifier); - if (rc) - goto out_free; - - cpu_notifier_register_done(); - /* Setup link change notification */ fcoe_dev_setup(); @@ -2652,12 +2440,6 @@ static int __init fcoe_init(void) return 0; out_free: - for_each_online_cpu(cpu) { - fcoe_percpu_thread_destroy(cpu); - } - - cpu_notifier_register_done(); - mutex_unlock(&fcoe_config_mutex); destroy_workqueue(fcoe_wq); return rc; @@ -2690,14 +2472,8 @@ static void __exit fcoe_exit(void) } rtnl_unlock(); - cpu_notifier_register_begin(); - - for_each_online_cpu(cpu) - fcoe_percpu_thread_destroy(cpu); - - __unregister_hotcpu_notifier(&fcoe_cpu_notifier); - - cpu_notifier_register_done(); + for_each_possible_cpu(cpu) + fcoe_thread_cleanup_local(cpu); mutex_unlock(&fcoe_config_mutex); diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index de7e3ee60f0c..c6fbbb6581d3 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -319,14 +319,16 @@ struct fcoe_transport { /** * struct fcoe_percpu_s - The context for FCoE receive thread(s) - * @thread: The thread context + * @kthread: The thread context (used by bnx2fc) + * @work: The work item (used by fcoe) * @fcoe_rx_list: The queue of pending packets to process * @page: The memory page for calculating frame trailer CRCs * @crc_eof_offset: The offset into the CRC page pointing to available * memory for a new trailer */ struct fcoe_percpu_s { - struct task_struct *thread; + struct task_struct *kthread; + struct work_struct work; struct sk_buff_head fcoe_rx_list; struct page *crc_eof_page; int crc_eof_offset; From fa06883281afaa158b2b350f16c377c448df6b61 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Thu, 30 Jun 2016 08:32:36 -0700 Subject: [PATCH 037/101] libfc: sanity check cpu number extracted from xid In the receive path libfc extracts a cpu number from the ox_id in the fiber channel header and uses that to do a per_cpu_ptr conversion. If, for some reason, a frame is received with an invalid ox_id, per_cpu_ptr will return an invalid pointer and the libfc receive path will panic the system trying to use it. I'm currently looking at such a case, and I don't yet know why a cpu number > nr_cpu_ids is appearing in an exchange id. But adding a sanity check in libfc prevents a system panic, and seems like good idea when dealing with frames coming in from the network. Signed-off-by: Chris Leech Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_exch.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 30f9ef0c0d4f..e72673b0a8fb 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -908,9 +908,17 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) { struct fc_exch_pool *pool; struct fc_exch *ep = NULL; + u16 cpu = xid & fc_cpu_mask; + + if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) { + printk_ratelimited(KERN_ERR + "libfc: lookup request for XID = %d, " + "indicates invalid CPU %d\n", xid, cpu); + return NULL; + } if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { - pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); + pool = per_cpu_ptr(mp->pool, cpu); spin_lock_bh(&pool->lock); ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); if (ep) { From 6a551c113252ca05d0f4ca307aa6d7118d0a5e45 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 4 Jul 2016 10:29:18 +0200 Subject: [PATCH 038/101] fc_fip: Update to latest FC-BB-6 draft Update to latest FC-BB-6 draft to include FIP VN2VN VLAN notifications and additional flags. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_ctlr.c | 8 ++++---- drivers/scsi/fnic/fnic_fcs.c | 4 ++-- drivers/scsi/fnic/fnic_fip.h | 8 -------- include/scsi/fc/fc_fip.h | 21 +++++++++++++++++---- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index ada4bdec9a4c..34b2b43f70e3 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -991,7 +991,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " "in FIP adv\n", desc->fip_dtype); /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + if (desc->fip_dtype < FIP_DT_NON_CRITICAL) return -EINVAL; break; } @@ -1232,7 +1232,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " "in FIP adv\n", desc->fip_dtype); /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + if (desc->fip_dtype < FIP_DT_NON_CRITICAL) goto drop; if (desc_cnt <= 2) { LIBFCOE_FIP_DBG(fip, "FIP descriptors " @@ -1410,7 +1410,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, break; default: /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + if (desc->fip_dtype < FIP_DT_NON_CRITICAL) goto err; break; } @@ -2338,7 +2338,7 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " "in FIP probe\n", dtype); /* standard says ignore unknown descriptors >= 128 */ - if (dtype < FIP_DT_VENDOR_BASE) + if (dtype < FIP_DT_NON_CRITICAL) return -EINVAL; break; } diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 67669a9e73c1..fe402d0cdbc3 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -359,7 +359,7 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic) vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); vlan->fip.fip_op = htons(FIP_OP_VLAN); - vlan->fip.fip_subcode = FIP_SC_VL_REQ; + vlan->fip.fip_subcode = FIP_SC_VL_NOTE; vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW); vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; @@ -551,7 +551,7 @@ static int fnic_fcoe_handle_fip_frame(struct fnic *fnic, struct sk_buff *skb) goto drop; /* pass it on to fcoe */ ret = 1; - } else if (op == FIP_OP_VLAN && sub == FIP_SC_VL_REP) { + } else if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) { /* set the vlan as used */ fnic_fcoe_process_vlan_resp(fnic, skb); ret = 0; diff --git a/drivers/scsi/fnic/fnic_fip.h b/drivers/scsi/fnic/fnic_fip.h index 87e74c2ab971..7761f33ab5d4 100644 --- a/drivers/scsi/fnic/fnic_fip.h +++ b/drivers/scsi/fnic/fnic_fip.h @@ -26,14 +26,6 @@ #define FINC_MAX_FLOGI_REJECTS 8 -/* - * FIP_DT_VLAN descriptor. - */ -struct fip_vlan_desc { - struct fip_desc fd_desc; - __be16 fd_vlan; -} __attribute__((packed)); - struct vlan { __be16 vid; __be16 type; diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h index ae25d4ab2548..9710254fd98c 100644 --- a/include/scsi/fc/fc_fip.h +++ b/include/scsi/fc/fc_fip.h @@ -22,7 +22,7 @@ /* * This version is based on: * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf - * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal) + * and T11 FC-BB-6 13-091v5.pdf (December 2013 VN2VN proposal) */ #define FIP_DEF_PRI 128 /* default selection priority */ @@ -109,8 +109,9 @@ enum fip_reset_subcode { * Subcodes for FIP_OP_VLAN. */ enum fip_vlan_subcode { - FIP_SC_VL_REQ = 1, /* request */ - FIP_SC_VL_REP = 2, /* reply */ + FIP_SC_VL_REQ = 1, /* vlan request */ + FIP_SC_VL_NOTE = 2, /* vlan notification */ + FIP_SC_VL_VN2VN_NOTE = 3, /* VN2VN vlan notification */ }; /* @@ -130,6 +131,8 @@ enum fip_vn2vn_subcode { enum fip_flag { FIP_FL_FPMA = 0x8000, /* supports FPMA fabric-provided MACs */ FIP_FL_SPMA = 0x4000, /* supports SPMA server-provided MACs */ + FIP_FL_FCF = 0x0020, /* originated from a controlling FCF */ + FIP_FL_FDF = 0x0010, /* originated from an FDF */ FIP_FL_REC_OR_P2P = 0x0008, /* configured addr or point-to-point */ FIP_FL_AVAIL = 0x0004, /* available for FLOGI/ELP */ FIP_FL_SOL = 0x0002, /* this is a solicited message */ @@ -161,7 +164,9 @@ enum fip_desc_type { FIP_DT_VLAN = 14, /* vlan number */ FIP_DT_FC4F = 15, /* FC-4 features */ FIP_DT_LIMIT, /* max defined desc_type + 1 */ - FIP_DT_VENDOR_BASE = 128, /* first vendor-specific desc_type */ + FIP_DT_NON_CRITICAL = 128, /* First non-critical descriptor */ + FIP_DT_CLR_VLINKS = 128, /* Clear virtual links reason code */ + FIP_DT_VENDOR_BASE = 241, /* first vendor-specific desc_type */ }; /* @@ -258,6 +263,14 @@ enum fip_fka_flags { /* FIP_DT_FKA flags */ +/* + * FIP_DT_VLAN descriptor + */ +struct fip_vlan_desc { + struct fip_desc fd_desc; + __be16 fd_vlan; /* Note: highest 4 bytes are unused */ +} __attribute__((packed)); + /* * FIP_DT_FC4F - FC-4 features. */ From 1917d42d14b744e7298872138dd281376a83a3fe Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 4 Jul 2016 10:29:19 +0200 Subject: [PATCH 039/101] fcoe: use enum for fip_mode The FIP mode is independent on the FIP state machine, so use a separate enum for that instead of overloading it with state machine values. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 6 +++--- drivers/scsi/fcoe/fcoe.c | 6 +++--- drivers/scsi/fcoe/fcoe_ctlr.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 2 +- include/scsi/libfcoe.h | 14 ++++++++------ 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index d6800afd0232..a5052dd8d7e6 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -57,7 +57,7 @@ static struct scsi_host_template bnx2fc_shost_template; static struct fc_function_template bnx2fc_transport_function; static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; static struct fc_function_template bnx2fc_vport_xport_function; -static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); +static int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode); static void __bnx2fc_destroy(struct bnx2fc_interface *interface); static int bnx2fc_destroy(struct net_device *net_device); static int bnx2fc_enable(struct net_device *netdev); @@ -2260,7 +2260,7 @@ enum bnx2fc_create_link_state { * Returns: 0 for success */ static int _bnx2fc_create(struct net_device *netdev, - enum fip_state fip_mode, + enum fip_mode fip_mode, enum bnx2fc_create_link_state link_state) { struct fcoe_ctlr_device *cdev; @@ -2412,7 +2412,7 @@ mod_err: * * Returns: 0 for success */ -static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) +static int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode) { return _bnx2fc_create(netdev, fip_mode, BNX2FC_CREATE_LINK_UP); } diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f7c7ccc156da..9c3742d52ca4 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -107,7 +107,7 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, ulong event, void *ptr); static bool fcoe_match(struct net_device *netdev); -static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); +static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode); static int fcoe_destroy(struct net_device *netdev); static int fcoe_enable(struct net_device *netdev); static int fcoe_disable(struct net_device *netdev); @@ -2133,7 +2133,7 @@ enum fcoe_create_link_state { * consolidation of code can be done when that interface is * removed. */ -static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode, +static int _fcoe_create(struct net_device *netdev, enum fip_mode fip_mode, enum fcoe_create_link_state link_state) { int rc = 0; @@ -2222,7 +2222,7 @@ out: * * Returns: 0 for success */ -static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) +static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode) { return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP); } diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 34b2b43f70e3..26a0685c74d1 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2864,7 +2864,7 @@ unlock: * when nothing is happening. */ static void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip, - enum fip_state fip_mode) + enum fip_mode fip_mode) { void *priv; diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index fe402d0cdbc3..0d532ae273eb 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -1308,7 +1308,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) } spin_unlock_irqrestore(&fnic->fnic_lock, flags); - if (fnic->ctlr.mode == FIP_ST_NON_FIP) + if (fnic->ctlr.mode == FIP_MODE_NON_FIP) return; spin_lock_irqsave(&fnic->vlans_lock, flags); diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index c6fbbb6581d3..bcc5c3e82977 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -78,10 +78,12 @@ enum fip_state { * The mode is the state that is to be entered after link up. * It must not change after fcoe_ctlr_init() sets it. */ -#define FIP_MODE_AUTO FIP_ST_AUTO -#define FIP_MODE_NON_FIP FIP_ST_NON_FIP -#define FIP_MODE_FABRIC FIP_ST_ENABLED -#define FIP_MODE_VN2VN FIP_ST_VNMP_START +enum fip_mode { + FIP_MODE_AUTO = FIP_ST_AUTO, + FIP_MODE_NON_FIP, + FIP_MODE_FABRIC, + FIP_MODE_VN2VN, +}; /** * struct fcoe_ctlr - FCoE Controller and FIP state @@ -124,7 +126,7 @@ enum fip_state { */ struct fcoe_ctlr { enum fip_state state; - enum fip_state mode; + enum fip_mode mode; struct fc_lport *lp; struct fcoe_fcf *sel_fcf; struct list_head fcfs; @@ -311,7 +313,7 @@ struct fcoe_transport { struct list_head list; bool (*match) (struct net_device *device); int (*alloc) (struct net_device *device); - int (*create) (struct net_device *device, enum fip_state fip_mode); + int (*create) (struct net_device *device, enum fip_mode fip_mode); int (*destroy) (struct net_device *device); int (*enable) (struct net_device *device); int (*disable) (struct net_device *device); From eb44c4e2fea0dacad615d42488bfd0a9053c9e9f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 4 Jul 2016 10:29:20 +0200 Subject: [PATCH 040/101] fcoe: fcoe->realdev is always set '->realdev' is always set, so this check is pointless. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 9c3742d52ca4..41c67e5ce5b9 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -770,9 +770,6 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev) fcoe = port->priv; realdev = fcoe->realdev; - if (!realdev) - return; - /* No FDMI state m/c for NPIV ports */ if (lport->vport) return; From a87dccc75bc4e97908191f1d191f25e2ec88664d Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 4 Jul 2016 10:29:21 +0200 Subject: [PATCH 041/101] fcoe: Update multicast addresses on FIP mode change When the FIP mode is changed we need to update the multicast addresses to ensure we get the correct frames. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 41c67e5ce5b9..61eda7498c90 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -115,7 +115,7 @@ static int fcoe_disable(struct net_device *netdev); /* fcoe_syfs control interface handlers */ static int fcoe_ctlr_alloc(struct net_device *netdev); static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev); - +static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev); static struct fc_seq *fcoe_elsct_send(struct fc_lport *, u32 did, struct fc_frame *, @@ -146,8 +146,9 @@ static void fcoe_set_vport_symbolic_name(struct fc_vport *); static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *); + static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { - .set_fcoe_ctlr_mode = fcoe_ctlr_set_fip_mode, + .set_fcoe_ctlr_mode = fcoe_ctlr_mode, .set_fcoe_ctlr_enabled = fcoe_ctlr_enabled, .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, @@ -1975,6 +1976,32 @@ static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev) }; } +/** + * fcoe_ctlr_mode() - Switch FIP mode + * @cdev: The FCoE Controller that is being modified + * + * When the FIP mode has been changed we need to update + * the multicast addresses to ensure we get the correct + * frames. + */ +static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev) +{ + struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); + struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); + + if (ctlr_dev->mode == FIP_CONN_TYPE_VN2VN && + ctlr->mode != FIP_MODE_VN2VN) { + dev_mc_del(fcoe->netdev, FIP_ALL_ENODE_MACS); + dev_mc_add(fcoe->netdev, FIP_ALL_VN2VN_MACS); + dev_mc_add(fcoe->netdev, FIP_ALL_P2P_MACS); + } else if (ctlr->mode != FIP_MODE_FABRIC) { + dev_mc_del(fcoe->netdev, FIP_ALL_VN2VN_MACS); + dev_mc_del(fcoe->netdev, FIP_ALL_P2P_MACS); + dev_mc_add(fcoe->netdev, FIP_ALL_ENODE_MACS); + } + fcoe_ctlr_set_fip_mode(ctlr_dev); +} + /** * fcoe_destroy() - Destroy a FCoE interface * @netdev : The net_device object the Ethernet interface to create on From d51bf96d7835abafbe2a251729554f0523a62203 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 7 Jul 2016 15:41:58 +0200 Subject: [PATCH 042/101] fcoe: use defines from ethtool for 20Gbit and 40Gbit speeds Use defines from ethtool for 20Gbit and 40Gbit speeds instead of magic numbers. Signed-off-by: Johannes Thumshirn Reviewed-by: Laurence Oberman Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 641c60e8fda3..7028dd37e5dd 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -133,10 +133,10 @@ int fcoe_link_speed_update(struct fc_lport *lport) case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; break; - case 20000: + case SPEED_20000: lport->link_speed = FC_PORTSPEED_20GBIT; break; - case 40000: + case SPEED_40000: lport->link_speed = FC_PORTSPEED_40GBIT; break; default: From d9083160c2f6ee456ea867ea2279c1fc6124e56f Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Fri, 8 Jul 2016 03:30:16 -0700 Subject: [PATCH 043/101] megaraid_sas: Do not fire MR_DCMD_PD_LIST_QUERY to controllers which do not support it There was an issue reported by Lucz Geza on Dell Perc 6i. As per issue reported, megaraid_sas driver goes into an infinite error reporting loop as soon as there is a change in the status of one of the arrays (degrade, resync online etc ). Below are the error logs reported continuously- Jun 25 08:49:30 ns8 kernel: [ 757.757017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 Jun 25 08:49:30 ns8 kernel: [ 757.778017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 Jun 25 08:49:30 ns8 kernel: [ 757.799017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 Jun 25 08:49:30 ns8 kernel: [ 757.820018] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 Jun 25 08:49:30 ns8 kernel: [ 757.841018] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 This issue is very much specific to controllers which do not support DCMD- MR_DCMD_PD_LIST_QUERY. In case of any hotplugging/rescanning of drives, AEN thread will be scheduled by driver and fire DCMD- MR_DCMD_PD_LIST_QUERY and if this DCMD is failed then driver will fail this event processing and will not go ahead for further events. This will cause infinite loop of same event getting retried infinitely and causing above mentioned logs. Fix for this problem is: not to fire DCMD MR_DCMD_PD_LIST_QUERY for controllers which do not support it and send DCMD SUCCESS status to AEN function so that it can go ahead with other event processing. Reported-by: Lucz Geza Cc: Signed-off-by: Sumit Saxena Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f4b0690450d2..2dab3dc2aa69 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4079,6 +4079,12 @@ megasas_get_pd_list(struct megasas_instance *instance) struct MR_PD_ADDRESS *pd_addr; dma_addr_t ci_h = 0; + if (instance->pd_list_not_supported) { + dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " + "not supported by firmware\n"); + return ret; + } + cmd = megasas_get_cmd(instance); if (!cmd) { From 68350a886e7df0269a14af888dd68be2ba9203ca Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 11 Jul 2016 13:34:55 +0900 Subject: [PATCH 044/101] scsi: remove current_cmnd field from struct scsi_device The field is only used by the 53c700 driver, so move it into the driver-private device data instead of having it in the common structure. Signed-off-by: Christoph Hellwig Reviewed-by: Tomas Henzl Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/53c700.c | 8 +++++--- drivers/scsi/53c700.h | 1 + include/scsi/scsi_device.h | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 55562019acf8..95e32a47face 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -1120,9 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, "reselection is tag %d, slot %p(%d)\n", hostdata->msgin[2], slot, slot->tag); } else { - struct scsi_cmnd *SCp; + struct NCR_700_Device_Parameters *p = SDp->hostdata; + struct scsi_cmnd *SCp = p->current_cmnd; - SCp = SDp->current_cmnd; if(unlikely(SCp == NULL)) { sdev_printk(KERN_ERR, SDp, "no saved request for untagged cmd\n"); @@ -1825,9 +1825,11 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) CDEBUG(KERN_DEBUG, SCp, "sending out tag %d, slot %p\n", slot->tag, slot); } else { + struct NCR_700_Device_Parameters *p = SCp->device->hostdata; + slot->tag = SCSI_NO_TAG; /* save current command for reselection */ - SCp->device->current_cmnd = SCp; + p->current_cmnd = SCp; } /* sanity check: some of the commands generated by the mid-layer * have an eccentric idea of their sc_data_direction */ diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index c893a5d3ff8d..f34c916b95bc 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -82,6 +82,7 @@ struct NCR_700_Device_Parameters { * cmnd[1], this could be in static storage */ unsigned char cmnd[MAX_COMMAND_SIZE]; __u8 depth; + struct scsi_cmnd *current_cmnd; /* currently active command */ }; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index a6c346df290d..8a9563144890 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -94,7 +94,6 @@ struct scsi_device { spinlock_t list_lock; struct list_head cmd_list; /* queue of in use SCSI Command structures */ struct list_head starved_entry; - struct scsi_cmnd *current_cmnd; /* currently active command */ unsigned short queue_depth; /* How deep of a queue we want */ unsigned short max_queue_depth; /* max queue depth */ unsigned short last_queue_full_depth; /* These two are used by */ From 00da9ffa3900d734e821f6b152faef88a5f0f304 Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Tue, 12 Jul 2016 16:02:07 -0500 Subject: [PATCH 045/101] ipr: Add new CCIN for new adapters support Add the appropriate definitions and table entries for new adapters support. Signed-off-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Acked-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 7 ++++++- drivers/scsi/ipr.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d6803a9e5ab8..01dc06562769 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -194,7 +194,8 @@ static const struct ipr_chip_t ipr_chip[] = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } }; static int ipr_max_bus_speeds[] = { @@ -10565,6 +10566,10 @@ static struct pci_device_id ipr_pci_table[] = { PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CD2, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCD, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_580A, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_580B, 0, 0, 0 }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 56c57068300a..1d42c7464dfc 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -60,6 +60,7 @@ #define PCI_DEVICE_ID_IBM_CROC_FPGA_E2 0x033D #define PCI_DEVICE_ID_IBM_CROCODILE 0x034A +#define PCI_DEVICE_ID_IBM_RATTLESNAKE 0x04DA #define IPR_SUBS_DEV_ID_2780 0x0264 #define IPR_SUBS_DEV_ID_5702 0x0266 @@ -111,6 +112,8 @@ #define IPR_SUBS_DEV_ID_2CCA 0x04C7 #define IPR_SUBS_DEV_ID_2CD2 0x04C8 #define IPR_SUBS_DEV_ID_2CCD 0x04C9 +#define IPR_SUBS_DEV_ID_580A 0x04FC +#define IPR_SUBS_DEV_ID_580B 0x04FB #define IPR_NAME "ipr" /* From cb05cbb389cd162db2d79e82ffaacc2451296ec2 Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Tue, 12 Jul 2016 16:02:08 -0500 Subject: [PATCH 046/101] ipr: Increase MSIX vectors number Increase MSIX vectors from 2 to 16 by default. Signed-off-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Acked-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 01dc06562769..1f539c288ae8 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -98,7 +98,7 @@ static unsigned int ipr_transop_timeout = 0; static unsigned int ipr_debug = 0; static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS; static unsigned int ipr_dual_ioa_raid = 1; -static unsigned int ipr_number_of_msix = 2; +static unsigned int ipr_number_of_msix = 16; static unsigned int ipr_fast_reboot; static DEFINE_SPINLOCK(ipr_driver_lock); @@ -222,7 +222,7 @@ module_param_named(max_devs, ipr_max_devs, int, 0); MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. " "[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]"); module_param_named(number_of_msix, ipr_number_of_msix, int, 0); -MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16). (default:2)"); +MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16). (default:16)"); module_param_named(fast_reboot, ipr_fast_reboot, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fast_reboot, "Skip adapter shutdown during reboot. Set to 1 to enable. (default: 0)"); MODULE_LICENSE("GPL"); From ef8d1d51aa5ebe4b17b5e837d520df1e398b7adb Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 6 Jul 2016 09:51:50 +0200 Subject: [PATCH 047/101] qla2xxx: setup data needed in ISR before setting up the ISR qla2xxx first calls request_irq() and then does the setup of the queue entry data needed in the interrupt handlers in when using MSI-X. This could lead to a NULL pointer dereference when an IRQ fires between the request_irq() call and the assignment of the qentry data structure to the rsp->msix field. A possible case for such a race would be in the kdump case when the HBA's IRQs are still enabled but the driver is undergoing a new initialisation and thus is not aware of already activated IRQs in the HBA. Signed-off-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a92a62dea793..ea8641b47c86 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3086,6 +3086,8 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) /* Enable MSI-X vectors for the base queue */ for (i = 0; i < 2; i++) { qentry = &ha->msix_entries[i]; + qentry->rsp = rsp; + rsp->msix = qentry; if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, @@ -3097,8 +3099,6 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) if (ret) goto msix_register_fail; qentry->have_irq = 1; - qentry->rsp = rsp; - rsp->msix = qentry; /* Register for CPU affinity notification. */ irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify); @@ -3119,12 +3119,12 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) */ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { qentry = &ha->msix_entries[ATIO_VECTOR]; + qentry->rsp = rsp; + rsp->msix = qentry; ret = request_irq(qentry->vector, qla83xx_msix_entries[ATIO_VECTOR].handler, 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp); qentry->have_irq = 1; - qentry->rsp = rsp; - rsp->msix = qentry; } msix_register_fail: From 83c3d3400c87d6d943bf97fce4b30f4fe6870253 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Tue, 12 Jul 2016 17:43:25 +0800 Subject: [PATCH 048/101] mpt3sas: Fix panic when aer correct error occurred The _scsih_pci_mmio_enabled called if scsih_pci_error_detected returns PCI_ERS_RESULT_CAN_RECOVER, at this point, read/write to the device still works, no need to reset slot. Or the mpt3sas_base_map_resources in scsih_pci_slot_reset will fail, and iounamp ioc->chip, then we will meet issue when read ioc->chip in mpt3sas_base_get_iocstate from _base_fault_reset_work. Cc: Sathya Prakash Cc: Chaitra P B Cc: Suganath Prabu Subramani Signed-off-by: Kefeng Wang Acked-by: Chaitra P B Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index cd6be7be0c5b..cd91a684c945 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -9035,8 +9035,11 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev) /* TODO - dump whatever for debugging purposes */ - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; + /* This called only if scsih_pci_error_detected returns + * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still + * works, no need to reset slot. + */ + return PCI_ERS_RESULT_RECOVERED; } /* From 757f9d7a801236a9c49468af9e64cd7c447c2f8e Mon Sep 17 00:00:00 2001 From: Manjunath M B Date: Tue, 12 Jul 2016 19:25:36 +0530 Subject: [PATCH 049/101] scsi: ufs: tc-dwc-g210 driver fix for 20-bit RMMI The code was checking on PA_CONNECTEDRXLANES and PA_CONNECTEDTXLANES attributes to program the Lane#1 attributes. The correct attributes are PA_AVAILRXDATALANES and PA_AVAILTXDATALANES respectively. Signed-off-by: Manjunath M B Tested-by: Joao Pinto Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/tc-dwc-g210.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c index d6c5388d41ac..70db6d999ca3 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.c +++ b/drivers/scsi/ufs/tc-dwc-g210.c @@ -187,9 +187,9 @@ static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba) }; /* Get the available lane count */ - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILRXDATALANES), &connected_rx_lanes); - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES), &connected_tx_lanes); if (connected_tx_lanes == 2) { From 9aa9cc4221f5154ed93e999662ccfef7b6a82e3e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jul 2016 13:19:05 +0900 Subject: [PATCH 050/101] scsi: remove the disable_blk_mq host flag We've had scsi-mq for 2.5 years now, so we can remove the unused flag to disable the code on a per-host basis that was put in for unexpected emergencies during bringup. Signed-off-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 2 -- drivers/scsi/scsi.c | 1 + include/scsi/scsi_host.h | 6 ++---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 1547bd93c70b..ba9af4a2bd2a 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -486,8 +486,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) else shost->dma_boundary = 0xffffffff; - shost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq; - device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); shost->shost_gendev.bus = &scsi_bus_type; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1deb6adc411f..1f36aca44394 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1160,6 +1160,7 @@ bool scsi_use_blk_mq = true; bool scsi_use_blk_mq = false; #endif module_param_named(use_blk_mq, scsi_use_blk_mq, bool, S_IWUSR | S_IRUGO); +EXPORT_SYMBOL_GPL(scsi_use_blk_mq); static int __init init_scsi(void) { diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 76e9d278c334..0dee7afa93d6 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -495,9 +495,6 @@ struct scsi_host_template { */ unsigned int cmd_size; struct scsi_host_cmd_pool *cmd_pool; - - /* temporary flag to disable blk-mq I/O path */ - bool disable_blk_mq; }; /* @@ -778,7 +775,8 @@ extern bool scsi_use_blk_mq; static inline bool shost_use_blk_mq(struct Scsi_Host *shost) { - return shost->use_blk_mq; + return scsi_use_blk_mq; + } extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); From 866d372e86aa256f3645b035c68350b08e182b9b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 14 Jul 2016 14:26:41 +0200 Subject: [PATCH 051/101] usb: MAINTAINERS: Oliver Neukum is the new uas maintainer Oliver Neukum is taking over uas maintainership from me and Gerd Hoffmann. Cc: Oliver Neukum Cc: Gerd Hoffmann Signed-off-by: Hans de Goede Acked-by: Oliver Neukum Acked-by: Gerd Hoffmann Signed-off-by: Martin K. Petersen --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c791298723d2..5a367e5368a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11802,8 +11802,7 @@ S: Maintained F: drivers/net/wireless/ath/ar5523/ USB ATTACHED SCSI -M: Hans de Goede -M: Gerd Hoffmann +M: Oliver Neukum L: linux-usb@vger.kernel.org L: linux-scsi@vger.kernel.org S: Maintained From 0073887ae5e23bfadb76fc5951b1fcd508a7a3bd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 15 Jul 2016 14:18:57 +0300 Subject: [PATCH 052/101] ibmvfc: prevent a potential deadlock My static checker complains that we need to unlock on this path. Seems true. Signed-off-by: Dan Carpenter Reviewed-by: Brian King Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvfc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index fc523c3e5019..ab67ec4b6bd6 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -4722,6 +4722,8 @@ static void ibmvfc_rport_add_thread(struct work_struct *work) tgt_dbg(tgt, "Setting rport roles\n"); fc_remote_port_rolechg(rport, tgt->ids.roles); put_device(&rport->dev); + } else { + spin_unlock_irqrestore(vhost->host->host_lock, flags); } kref_put(&tgt->kref, ibmvfc_release_tgt); From 310429ef11e828e26c5ef222b6793bef1fc8cd6e Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:54 -0700 Subject: [PATCH 053/101] lpfc: Fix Transgression Flag of Optical Element descriptor for RDP on Linux Fix Transgression Flag of Optical Element descriptor for RDP on Linux Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 12 ++++ drivers/scsi/lpfc/lpfc_els.c | 101 ++++++++++++++++++++++++++-------- drivers/scsi/lpfc/lpfc_hw.h | 6 ++ drivers/scsi/lpfc/lpfc_hw4.h | 6 +- drivers/scsi/lpfc/lpfc_init.c | 2 + 5 files changed, 101 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index d5bd420595c1..c6ade9bb5280 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -999,6 +999,18 @@ struct lpfc_hba { spinlock_t devicelock; /* lock for luns list */ mempool_t *device_data_mem_pool; struct list_head luns; +#define LPFC_TRANSGRESSION_HIGH_TEMPERATURE 0x0080 +#define LPFC_TRANSGRESSION_LOW_TEMPERATURE 0x0040 +#define LPFC_TRANSGRESSION_HIGH_VOLTAGE 0x0020 +#define LPFC_TRANSGRESSION_LOW_VOLTAGE 0x0010 +#define LPFC_TRANSGRESSION_HIGH_TXBIAS 0x0008 +#define LPFC_TRANSGRESSION_LOW_TXBIAS 0x0004 +#define LPFC_TRANSGRESSION_HIGH_TXPOWER 0x0002 +#define LPFC_TRANSGRESSION_LOW_TXPOWER 0x0001 +#define LPFC_TRANSGRESSION_HIGH_RXPOWER 0x8000 +#define LPFC_TRANSGRESSION_LOW_RXPOWER 0x4000 + uint16_t sfp_alarm; + uint16_t sfp_warning; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0498f5760d2b..300131ad5a52 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4730,9 +4730,10 @@ lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, } void -lpfc_rdp_res_oed_temp_desc(struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) +lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, + struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { - uint32_t flags; + uint32_t flags = 0; desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); @@ -4743,17 +4744,27 @@ lpfc_rdp_res_oed_temp_desc(struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) cpu_to_be16(page_a2[SSF_TEMP_HIGH_WARNING]); desc->oed_info.lo_warning = cpu_to_be16(page_a2[SSF_TEMP_LOW_WARNING]); - flags = 0xf; /* All four are valid */ + + if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TEMPERATURE) + flags |= RDP_OET_HIGH_ALARM; + if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TEMPERATURE) + flags |= RDP_OET_LOW_ALARM; + if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TEMPERATURE) + flags |= RDP_OET_HIGH_WARNING; + if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TEMPERATURE) + flags |= RDP_OET_LOW_WARNING; + flags |= ((0xf & RDP_OED_TEMPERATURE) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); } void -lpfc_rdp_res_oed_voltage_desc(struct fc_rdp_oed_sfp_desc *desc, +lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, + struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { - uint32_t flags; + uint32_t flags = 0; desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); @@ -4764,17 +4775,27 @@ lpfc_rdp_res_oed_voltage_desc(struct fc_rdp_oed_sfp_desc *desc, cpu_to_be16(page_a2[SSF_VOLTAGE_HIGH_WARNING]); desc->oed_info.lo_warning = cpu_to_be16(page_a2[SSF_VOLTAGE_LOW_WARNING]); - flags = 0xf; /* All four are valid */ + + if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_VOLTAGE) + flags |= RDP_OET_HIGH_ALARM; + if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_VOLTAGE) + flags |= RDP_OET_LOW_ALARM; + if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_VOLTAGE) + flags |= RDP_OET_HIGH_WARNING; + if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_VOLTAGE) + flags |= RDP_OET_LOW_WARNING; + flags |= ((0xf & RDP_OED_VOLTAGE) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); } void -lpfc_rdp_res_oed_txbias_desc(struct fc_rdp_oed_sfp_desc *desc, +lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, + struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { - uint32_t flags; + uint32_t flags = 0; desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); @@ -4785,17 +4806,27 @@ lpfc_rdp_res_oed_txbias_desc(struct fc_rdp_oed_sfp_desc *desc, cpu_to_be16(page_a2[SSF_BIAS_HIGH_WARNING]); desc->oed_info.lo_warning = cpu_to_be16(page_a2[SSF_BIAS_LOW_WARNING]); - flags = 0xf; /* All four are valid */ + + if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXBIAS) + flags |= RDP_OET_HIGH_ALARM; + if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TXBIAS) + flags |= RDP_OET_LOW_ALARM; + if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TXBIAS) + flags |= RDP_OET_HIGH_WARNING; + if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TXBIAS) + flags |= RDP_OET_LOW_WARNING; + flags |= ((0xf & RDP_OED_TXBIAS) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); } void -lpfc_rdp_res_oed_txpower_desc(struct fc_rdp_oed_sfp_desc *desc, +lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, + struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { - uint32_t flags; + uint32_t flags = 0; desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); @@ -4806,7 +4837,16 @@ lpfc_rdp_res_oed_txpower_desc(struct fc_rdp_oed_sfp_desc *desc, cpu_to_be16(page_a2[SSF_TXPOWER_HIGH_WARNING]); desc->oed_info.lo_warning = cpu_to_be16(page_a2[SSF_TXPOWER_LOW_WARNING]); - flags = 0xf; /* All four are valid */ + + if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXPOWER) + flags |= RDP_OET_HIGH_ALARM; + if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TXPOWER) + flags |= RDP_OET_LOW_ALARM; + if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TXPOWER) + flags |= RDP_OET_HIGH_WARNING; + if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TXPOWER) + flags |= RDP_OET_LOW_WARNING; + flags |= ((0xf & RDP_OED_TXPOWER) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); @@ -4814,10 +4854,11 @@ lpfc_rdp_res_oed_txpower_desc(struct fc_rdp_oed_sfp_desc *desc, void -lpfc_rdp_res_oed_rxpower_desc(struct fc_rdp_oed_sfp_desc *desc, +lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, + struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { - uint32_t flags; + uint32_t flags = 0; desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); @@ -4828,7 +4869,16 @@ lpfc_rdp_res_oed_rxpower_desc(struct fc_rdp_oed_sfp_desc *desc, cpu_to_be16(page_a2[SSF_RXPOWER_HIGH_WARNING]); desc->oed_info.lo_warning = cpu_to_be16(page_a2[SSF_RXPOWER_LOW_WARNING]); - flags = 0xf; /* All four are valid */ + + if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_RXPOWER) + flags |= RDP_OET_HIGH_ALARM; + if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_RXPOWER) + flags |= RDP_OET_LOW_ALARM; + if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_RXPOWER) + flags |= RDP_OET_HIGH_WARNING; + if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_RXPOWER) + flags |= RDP_OET_LOW_WARNING; + flags |= ((0xf & RDP_OED_RXPOWER) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); @@ -4977,6 +5027,7 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, struct ls_rjt *stat; struct fc_rdp_res_frame *rdp_res; uint32_t cmdsize; + uint16_t *flag_ptr; int rc, fec_size; if (status != SUCCESS) @@ -5008,6 +5059,12 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, memset(pcmd, 0, sizeof(struct fc_rdp_res_frame)); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; + /* Update Alarm and Warning */ + flag_ptr = (uint16_t *)(rdp_context->page_a2 + SSF_ALARM_FLAGS); + phba->sfp_alarm |= *flag_ptr; + flag_ptr = (uint16_t *)(rdp_context->page_a2 + SSF_WARNING_FLAGS); + phba->sfp_warning |= *flag_ptr; + /* For RDP payload */ lpfc_rdp_res_link_service(&rdp_res->link_service_desc, ELS_CMD_RDP); @@ -5015,21 +5072,21 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, rdp_context->page_a0, rdp_context->page_a2); lpfc_rdp_res_speed(&rdp_res->portspeed_desc, phba); lpfc_rdp_res_link_error(&rdp_res->link_error_desc, - &rdp_context->link_stat); + &rdp_context->link_stat); lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba); lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc, - vport, ndlp); + vport, ndlp); lpfc_rdp_res_bbc_desc(&rdp_res->bbc_desc, &rdp_context->link_stat, vport); - lpfc_rdp_res_oed_temp_desc(&rdp_res->oed_temp_desc, + lpfc_rdp_res_oed_temp_desc(phba, &rdp_res->oed_temp_desc, rdp_context->page_a2); - lpfc_rdp_res_oed_voltage_desc(&rdp_res->oed_voltage_desc, + lpfc_rdp_res_oed_voltage_desc(phba, &rdp_res->oed_voltage_desc, rdp_context->page_a2); - lpfc_rdp_res_oed_txbias_desc(&rdp_res->oed_txbias_desc, + lpfc_rdp_res_oed_txbias_desc(phba, &rdp_res->oed_txbias_desc, rdp_context->page_a2); - lpfc_rdp_res_oed_txpower_desc(&rdp_res->oed_txpower_desc, + lpfc_rdp_res_oed_txpower_desc(phba, &rdp_res->oed_txpower_desc, rdp_context->page_a2); - lpfc_rdp_res_oed_rxpower_desc(&rdp_res->oed_rxpower_desc, + lpfc_rdp_res_oed_rxpower_desc(phba, &rdp_res->oed_rxpower_desc, rdp_context->page_a2); lpfc_rdp_res_opd_desc(&rdp_res->opd_desc, rdp_context->page_a0, vport); fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc, diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 39f0fd000d2c..5385faf5f545 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1206,6 +1206,12 @@ struct fc_rdp_bbc_desc { struct fc_rdp_bbc_info bbc_info; }; +/* Optical Element Type Transgression Flags */ +#define RDP_OET_LOW_WARNING 0x1 +#define RDP_OET_HIGH_WARNING 0x2 +#define RDP_OET_LOW_ALARM 0x4 +#define RDP_OET_HIGH_ALARM 0x8 + #define RDP_OED_TEMPERATURE 0x1 #define RDP_OED_VOLTAGE 0x2 #define RDP_OED_TXBIAS 0x3 diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 0c7070bf2813..8a5e08dd9f99 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2590,10 +2590,8 @@ struct lpfc_mbx_memory_dump_type3 { #define SFF_RXPOWER_B1 104 #define SFF_RXPOWER_B0 105 #define SSF_STATUS_CONTROL 110 -#define SSF_ALARM_FLAGS_B1 112 -#define SSF_ALARM_FLAGS_B0 113 -#define SSF_WARNING_FLAGS_B1 116 -#define SSF_WARNING_FLAGS_B0 117 +#define SSF_ALARM_FLAGS 112 +#define SSF_WARNING_FLAGS 116 #define SSF_EXT_TATUS_CONTROL_B1 118 #define SSF_EXT_TATUS_CONTROL_B0 119 #define SSF_A2_VENDOR_SPECIFIC 120 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b43f7ac9812c..bce73b496421 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1681,6 +1681,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) "taking port offline Data: x%x x%x\n", reg_err1, reg_err2); + phba->sfp_alarm |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE; temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; temp_event_data.event_code = LPFC_CRIT_TEMP; temp_event_data.data = 0xFFFFFFFF; @@ -4107,6 +4108,7 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "3190 Over Temperature:%d Celsius- Port Name %c\n", acqe_sli->event_data1, port_name); + phba->sfp_warning |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE; shost = lpfc_shost_from_vport(phba->pport); fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(temp_event_data), From 6c92d1d0ce4efffc67ba6f4ce0c7f970c15af390 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:55 -0700 Subject: [PATCH 054/101] lpfc: Correct RDP response sizing issue Correct RDP response sizing issue Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 113 ++++++++++++++++++++++------------- drivers/scsi/lpfc/lpfc_hw.h | 26 +++----- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 300131ad5a52..0d05e1a23523 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4609,7 +4609,7 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) return sentplogi; } -void +uint32_t lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc, uint32_t word0) { @@ -4617,9 +4617,11 @@ lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc, desc->tag = cpu_to_be32(RDP_LINK_SERVICE_DESC_TAG); desc->payload.els_req = word0; desc->length = cpu_to_be32(sizeof(desc->payload)); + + return sizeof(struct fc_rdp_link_service_desc); } -void +uint32_t lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc, uint8_t *page_a0, uint8_t *page_a2) { @@ -4680,9 +4682,11 @@ lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc, desc->sfp_info.flags = cpu_to_be16(flag); desc->length = cpu_to_be32(sizeof(desc->sfp_info)); + + return sizeof(struct fc_rdp_sfp_desc); } -void +uint32_t lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc, READ_LNK_VAR *stat) { @@ -4707,9 +4711,11 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc, desc->info.link_status.invalid_crc_cnt = cpu_to_be32(stat->crcCnt); desc->length = cpu_to_be32(sizeof(desc->info)); + + return sizeof(struct fc_rdp_link_error_status_desc); } -void +uint32_t lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, struct lpfc_vport *vport) { @@ -4727,9 +4733,11 @@ lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, desc->bbc_info.rtt = 0; desc->length = cpu_to_be32(sizeof(desc->bbc_info)); + + return sizeof(struct fc_rdp_bbc_desc); } -void +uint32_t lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { @@ -4757,9 +4765,10 @@ lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, flags |= ((0xf & RDP_OED_TEMPERATURE) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); + return sizeof(struct fc_rdp_oed_sfp_desc); } -void +uint32_t lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -4788,9 +4797,10 @@ lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, flags |= ((0xf & RDP_OED_VOLTAGE) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); + return sizeof(struct fc_rdp_oed_sfp_desc); } -void +uint32_t lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -4819,9 +4829,10 @@ lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, flags |= ((0xf & RDP_OED_TXBIAS) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); + return sizeof(struct fc_rdp_oed_sfp_desc); } -void +uint32_t lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -4850,10 +4861,11 @@ lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, flags |= ((0xf & RDP_OED_TXPOWER) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); + return sizeof(struct fc_rdp_oed_sfp_desc); } -void +uint32_t lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -4882,9 +4894,10 @@ lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, flags |= ((0xf & RDP_OED_RXPOWER) << RDP_OED_TYPE_SHIFT); desc->oed_info.function_flags = cpu_to_be32(flags); desc->length = cpu_to_be32(sizeof(desc->oed_info)); + return sizeof(struct fc_rdp_oed_sfp_desc); } -void +uint32_t lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc, uint8_t *page_a0, struct lpfc_vport *vport) { @@ -4895,9 +4908,10 @@ lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc, memcpy(desc->opd_info.revision, &page_a0[SSF_VENDOR_REV], 2); memcpy(desc->opd_info.date, &page_a0[SSF_DATE_CODE], 8); desc->length = cpu_to_be32(sizeof(desc->opd_info)); + return sizeof(struct fc_rdp_opd_sfp_desc); } -int +uint32_t lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat) { if (bf_get(lpfc_read_link_stat_gec2, stat) == 0) @@ -4914,7 +4928,7 @@ lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat) return sizeof(struct fc_fec_rdp_desc); } -void +uint32_t lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) { uint16_t rdp_cap = 0; @@ -4973,9 +4987,10 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) desc->info.port_speed.capabilities = cpu_to_be16(rdp_cap); desc->length = cpu_to_be32(sizeof(desc->info)); + return sizeof(struct fc_rdp_port_speed_desc); } -void +uint32_t lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc, struct lpfc_hba *phba) { @@ -4989,9 +5004,10 @@ lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc, sizeof(desc->port_names.wwpn)); desc->length = cpu_to_be32(sizeof(desc->port_names)); + return sizeof(struct fc_rdp_port_name_desc); } -void +uint32_t lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -5012,6 +5028,7 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, } desc->length = cpu_to_be32(sizeof(desc->port_names)); + return sizeof(struct fc_rdp_port_name_desc); } void @@ -5026,9 +5043,9 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, uint8_t *pcmd; struct ls_rjt *stat; struct fc_rdp_res_frame *rdp_res; - uint32_t cmdsize; + uint32_t cmdsize, len; uint16_t *flag_ptr; - int rc, fec_size; + int rc; if (status != SUCCESS) goto error; @@ -5066,38 +5083,54 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, phba->sfp_warning |= *flag_ptr; /* For RDP payload */ - lpfc_rdp_res_link_service(&rdp_res->link_service_desc, ELS_CMD_RDP); + len = 8; + len += lpfc_rdp_res_link_service((struct fc_rdp_link_service_desc *) + (len + pcmd), ELS_CMD_RDP); - lpfc_rdp_res_sfp_desc(&rdp_res->sfp_desc, + len += lpfc_rdp_res_sfp_desc((struct fc_rdp_sfp_desc *)(len + pcmd), rdp_context->page_a0, rdp_context->page_a2); - lpfc_rdp_res_speed(&rdp_res->portspeed_desc, phba); - lpfc_rdp_res_link_error(&rdp_res->link_error_desc, - &rdp_context->link_stat); - lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba); - lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc, - vport, ndlp); - lpfc_rdp_res_bbc_desc(&rdp_res->bbc_desc, &rdp_context->link_stat, - vport); - lpfc_rdp_res_oed_temp_desc(phba, &rdp_res->oed_temp_desc, - rdp_context->page_a2); - lpfc_rdp_res_oed_voltage_desc(phba, &rdp_res->oed_voltage_desc, - rdp_context->page_a2); - lpfc_rdp_res_oed_txbias_desc(phba, &rdp_res->oed_txbias_desc, - rdp_context->page_a2); - lpfc_rdp_res_oed_txpower_desc(phba, &rdp_res->oed_txpower_desc, - rdp_context->page_a2); - lpfc_rdp_res_oed_rxpower_desc(phba, &rdp_res->oed_rxpower_desc, - rdp_context->page_a2); - lpfc_rdp_res_opd_desc(&rdp_res->opd_desc, rdp_context->page_a0, vport); - fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc, + len += lpfc_rdp_res_speed((struct fc_rdp_port_speed_desc *)(len + pcmd), + phba); + len += lpfc_rdp_res_link_error((struct fc_rdp_link_error_status_desc *) + (len + pcmd), &rdp_context->link_stat); + len += lpfc_rdp_res_diag_port_names((struct fc_rdp_port_name_desc *) + (len + pcmd), phba); + len += lpfc_rdp_res_attach_port_names((struct fc_rdp_port_name_desc *) + (len + pcmd), vport, ndlp); + len += lpfc_rdp_res_fec_desc((struct fc_fec_rdp_desc *)(len + pcmd), &rdp_context->link_stat); - rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE); + /* Check if nport is logged, BZ190632 */ + if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) + goto lpfc_skip_descriptor; + + len += lpfc_rdp_res_bbc_desc((struct fc_rdp_bbc_desc *)(len + pcmd), + &rdp_context->link_stat, vport); + len += lpfc_rdp_res_oed_temp_desc(phba, + (struct fc_rdp_oed_sfp_desc *)(len + pcmd), + rdp_context->page_a2); + len += lpfc_rdp_res_oed_voltage_desc(phba, + (struct fc_rdp_oed_sfp_desc *)(len + pcmd), + rdp_context->page_a2); + len += lpfc_rdp_res_oed_txbias_desc(phba, + (struct fc_rdp_oed_sfp_desc *)(len + pcmd), + rdp_context->page_a2); + len += lpfc_rdp_res_oed_txpower_desc(phba, + (struct fc_rdp_oed_sfp_desc *)(len + pcmd), + rdp_context->page_a2); + len += lpfc_rdp_res_oed_rxpower_desc(phba, + (struct fc_rdp_oed_sfp_desc *)(len + pcmd), + rdp_context->page_a2); + len += lpfc_rdp_res_opd_desc((struct fc_rdp_opd_sfp_desc *)(len + pcmd), + rdp_context->page_a0, vport); + +lpfc_skip_descriptor: + rdp_res->length = cpu_to_be32(len - 8); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; /* Now that we know the true size of the payload, update the BPL */ bpl = (struct ulp_bde64 *) (((struct lpfc_dmabuf *)(elsiocb->context3))->virt); - bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8); + bpl->tus.f.bdeSize = len; bpl->tus.f.bdeFlags = 0; bpl->tus.w = le32_to_cpu(bpl->tus.w); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 5385faf5f545..829a114d505a 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1267,27 +1267,17 @@ struct fc_rdp_res_frame { struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */ struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22-27 */ struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */ - struct fc_rdp_bbc_desc bbc_desc; /* FC Word 34-38*/ - struct fc_rdp_oed_sfp_desc oed_temp_desc; /* FC Word 39-43*/ - struct fc_rdp_oed_sfp_desc oed_voltage_desc; /* FC word 44-48*/ - struct fc_rdp_oed_sfp_desc oed_txbias_desc; /* FC word 49-53*/ - struct fc_rdp_oed_sfp_desc oed_txpower_desc; /* FC word 54-58*/ - struct fc_rdp_oed_sfp_desc oed_rxpower_desc; /* FC word 59-63*/ - struct fc_rdp_opd_sfp_desc opd_desc; /* FC word 64-80*/ - struct fc_fec_rdp_desc fec_desc; /* FC word 81-84*/ + struct fc_fec_rdp_desc fec_desc; /* FC word 34-37*/ + struct fc_rdp_bbc_desc bbc_desc; /* FC Word 38-42*/ + struct fc_rdp_oed_sfp_desc oed_temp_desc; /* FC Word 43-47*/ + struct fc_rdp_oed_sfp_desc oed_voltage_desc; /* FC word 48-52*/ + struct fc_rdp_oed_sfp_desc oed_txbias_desc; /* FC word 53-57*/ + struct fc_rdp_oed_sfp_desc oed_txpower_desc; /* FC word 58-62*/ + struct fc_rdp_oed_sfp_desc oed_rxpower_desc; /* FC word 63-67*/ + struct fc_rdp_opd_sfp_desc opd_desc; /* FC word 68-84*/ }; -#define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \ - + sizeof(struct fc_rdp_sfp_desc) \ - + sizeof(struct fc_rdp_port_speed_desc) \ - + sizeof(struct fc_rdp_link_error_status_desc) \ - + (sizeof(struct fc_rdp_port_name_desc) * 2) \ - + sizeof(struct fc_rdp_bbc_desc) \ - + (sizeof(struct fc_rdp_oed_sfp_desc) * 5) \ - + sizeof(struct fc_rdp_opd_sfp_desc)) - - /******** FDMI ********/ /* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */ From 65791f1f90aade6a02877f9bb7c63f67b35f138c Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:56 -0700 Subject: [PATCH 055/101] lpfc: Add recovery from adapter parity errors on some SLI4 adapters Add recovery from adapter parity errors on some SLI4 adapters Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 2 + drivers/scsi/lpfc/lpfc_hw4.h | 23 +++++++ drivers/scsi/lpfc/lpfc_init.c | 118 +++++++++++++++++++++++++--------- drivers/scsi/lpfc/lpfc_sli.c | 45 +++++++++++-- drivers/scsi/lpfc/lpfc_sli4.h | 2 + 5 files changed, 155 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index c6ade9bb5280..64d6e3399a68 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -647,6 +647,7 @@ struct lpfc_hba { #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ #define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */ #define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ +#define HBA_RECOVERABLE_UE 0x20000 /* Firmware supports recoverable UE */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; @@ -827,6 +828,7 @@ struct lpfc_hba { struct timer_list fcp_poll_timer; struct timer_list eratt_poll; + uint32_t eratt_poll_interval; /* * stat counters diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8a5e08dd9f99..8738b3dc87f1 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -544,6 +544,8 @@ struct lpfc_register { uint32_t word0; }; +#define LPFC_PORT_SEM_UE_RECOVERABLE 0xE000 +#define LPFC_PORT_SEM_MASK 0xF000 /* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */ #define LPFC_UERR_STATUS_HI 0x00A4 #define LPFC_UERR_STATUS_LO 0x00A0 @@ -937,6 +939,7 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_READ_OBJECT_LIST 0xAD #define LPFC_MBOX_OPCODE_DELETE_OBJECT 0xAE #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5 +#define LPFC_MBOX_OPCODE_SET_FEATURES 0xBF /* FCoE Opcodes */ #define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01 @@ -2887,6 +2890,25 @@ struct lpfc_sli4_parameters { #define cfg_ext_embed_cb_WORD word19 }; +#define LPFC_SET_UE_RECOVERY 0x10 +struct lpfc_mbx_set_feature { + struct mbox_header header; + uint32_t feature; + uint32_t param_len; + uint32_t word6; +#define lpfc_mbx_set_feature_UER_SHIFT 0 +#define lpfc_mbx_set_feature_UER_MASK 0x00000001 +#define lpfc_mbx_set_feature_UER_WORD word6 + uint32_t word7; +#define lpfc_mbx_set_feature_UERP_SHIFT 0 +#define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff +#define lpfc_mbx_set_feature_UERP_WORD word7 +#define lpfc_mbx_set_feature_UESR_SHIFT 16 +#define lpfc_mbx_set_feature_UESR_MASK 0x0000ffff +#define lpfc_mbx_set_feature_UESR_WORD word7 +}; + + struct lpfc_mbx_get_sli4_parameters { struct mbox_header header; struct lpfc_sli4_parameters sli4_parameters; @@ -3279,6 +3301,7 @@ struct lpfc_mqe { struct lpfc_mbx_get_prof_cfg get_prof_cfg; struct lpfc_mbx_wr_object wr_object; struct lpfc_mbx_get_port_name get_port_name; + struct lpfc_mbx_set_feature set_feature; struct lpfc_mbx_memory_dump_type3 mem_dump_type3; struct lpfc_mbx_nop nop; } un; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bce73b496421..f11e33ee4132 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -568,7 +568,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->last_completion_time = jiffies; /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, - jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); + jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); if (phba->hba_flag & LINK_DISABLED) { lpfc_printf_log(phba, @@ -1587,35 +1587,38 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, int rc; uint32_t intr_mode; - /* - * On error status condition, driver need to wait for port - * ready before performing reset. - */ - rc = lpfc_sli4_pdev_status_reg_wait(phba); - if (!rc) { - /* need reset: attempt for port recovery */ - if (en_rn_msg) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2887 Reset Needed: Attempting Port " - "Recovery...\n"); - lpfc_offline_prep(phba, mbx_action); - lpfc_offline(phba); - /* release interrupt for possible resource change */ - lpfc_sli4_disable_intr(phba); - lpfc_sli_brdrestart(phba); - /* request and enable interrupt */ - intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3175 Failed to enable interrupt\n"); - return -EIO; - } else { - phba->intr_mode = intr_mode; - } - rc = lpfc_online(phba); - if (rc == 0) - lpfc_unblock_mgmt_io(phba); + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_2) { + /* + * On error status condition, driver need to wait for port + * ready before performing reset. + */ + rc = lpfc_sli4_pdev_status_reg_wait(phba); + if (!rc) + return rc; } + /* need reset: attempt for port recovery */ + if (en_rn_msg) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2887 Reset Needed: Attempting Port " + "Recovery...\n"); + lpfc_offline_prep(phba, mbx_action); + lpfc_offline(phba); + /* release interrupt for possible resource change */ + lpfc_sli4_disable_intr(phba); + lpfc_sli_brdrestart(phba); + /* request and enable interrupt */ + intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); + if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3175 Failed to enable interrupt\n"); + return -EIO; + } + phba->intr_mode = intr_mode; + rc = lpfc_online(phba); + if (rc == 0) + lpfc_unblock_mgmt_io(phba); + return rc; } @@ -1636,10 +1639,11 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) struct lpfc_register portstat_reg = {0}; uint32_t reg_err1, reg_err2; uint32_t uerrlo_reg, uemasklo_reg; - uint32_t pci_rd_rc1, pci_rd_rc2; + uint32_t smphr_port_status = 0, pci_rd_rc1, pci_rd_rc2; bool en_rn_msg = true; struct temp_event temp_event_data; - int rc; + struct lpfc_register portsmphr_reg; + int rc, i; /* If the pci channel is offline, ignore possible errors, since * we cannot communicate with the pci card anyway. @@ -1647,6 +1651,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (pci_channel_offline(phba->pcidev)) return; + memset(&portsmphr_reg, 0, sizeof(portsmphr_reg)); if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { case LPFC_SLI_INTF_IF_TYPE_0: @@ -1659,6 +1664,55 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) /* consider PCI bus read error as pci_channel_offline */ if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO) return; + if (!(phba->hba_flag & HBA_RECOVERABLE_UE)) { + lpfc_sli4_offline_eratt(phba); + return; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "7623 Checking UE recoverable"); + + for (i = 0; i < phba->sli4_hba.ue_to_sr / 1000; i++) { + if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr, + &portsmphr_reg.word0)) + continue; + + smphr_port_status = bf_get(lpfc_port_smphr_port_status, + &portsmphr_reg); + if ((smphr_port_status & LPFC_PORT_SEM_MASK) == + LPFC_PORT_SEM_UE_RECOVERABLE) + break; + /*Sleep for 1Sec, before checking SEMAPHORE */ + msleep(1000); + } + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "4827 smphr_port_status x%x : Waited %dSec", + smphr_port_status, i); + + /* Recoverable UE, reset the HBA device */ + if ((smphr_port_status & LPFC_PORT_SEM_MASK) == + LPFC_PORT_SEM_UE_RECOVERABLE) { + for (i = 0; i < 20; i++) { + msleep(1000); + if (!lpfc_readl(phba->sli4_hba.PSMPHRregaddr, + &portsmphr_reg.word0) && + (LPFC_POST_STAGE_PORT_READY == + bf_get(lpfc_port_smphr_port_status, + &portsmphr_reg))) { + rc = lpfc_sli4_port_sta_fn_reset(phba, + LPFC_MBX_NO_WAIT, en_rn_msg); + if (rc == 0) + return; + lpfc_printf_log(phba, + KERN_ERR, LOG_INIT, + "4215 Failed to recover UE"); + break; + } + } + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "7624 Firmware not ready: Failing UE recovery," + " waited %dSec", i); lpfc_sli4_offline_eratt(phba); break; @@ -5365,6 +5419,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_free_bsmbx; } } + /* * Get sli4 parameters that override parameters from Port capabilities. * If this call fails, it isn't critical unless the SLI4 parameters come @@ -6093,6 +6148,7 @@ lpfc_hba_alloc(struct pci_dev *pdev) kfree(phba); return NULL; } + phba->eratt_poll_interval = LPFC_ERATT_POLL_INTERVAL; spin_lock_init(&phba->ct_ev_lock); INIT_LIST_HEAD(&phba->ct_ev_waiters); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 70edf21ae1b9..b3a781d38fa8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2947,8 +2947,8 @@ void lpfc_poll_eratt(unsigned long ptr) else cnt = (sli_intr - phba->sli.slistat.sli_prev_intr); - /* 64-bit integer division not supporte on 32-bit x86 - use do_div */ - do_div(cnt, LPFC_ERATT_POLL_INTERVAL); + /* 64-bit integer division not supported on 32-bit x86 - use do_div */ + do_div(cnt, phba->eratt_poll_interval); phba->sli.slistat.sli_ips = cnt; phba->sli.slistat.sli_prev_intr = sli_intr; @@ -2963,7 +2963,7 @@ void lpfc_poll_eratt(unsigned long ptr) /* Restart the timer for next eratt poll */ mod_timer(&phba->eratt_poll, jiffies + - msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); return; } @@ -5690,6 +5690,40 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) return rc; } +void +lpfc_set_features(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mbox = NULL; + uint32_t len; + int rc; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return; + len = sizeof(struct lpfc_mbx_set_feature) - + sizeof(struct lpfc_sli4_cfg_mhdr); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_SET_FEATURES, len, + LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_set_feature_UER, + &mbox->u.mqe.un.set_feature, 1); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY; + mbox->u.mqe.un.set_feature.param_len = 8; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + + if (rc != MBX_SUCCESS) { + mempool_free(mbox, phba->mbox_mem_pool); + return; + } + phba->hba_flag |= HBA_RECOVERABLE_UE; + phba->eratt_poll_interval = 1; /* Set 1Sec interval to detect UE */ + phba->sli4_hba.ue_to_sr = bf_get(lpfc_mbx_set_feature_UESR, + &mbox->u.mqe.un.set_feature); + phba->sli4_hba.ue_to_rp = bf_get(lpfc_mbx_set_feature_UERP, + &mbox->u.mqe.un.set_feature); + mempool_free(mbox, phba->mbox_mem_pool); +} + /** * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents. * @phba: Pointer to HBA context object. @@ -6414,6 +6448,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->pport->cfg_lun_queue_depth = rc; } + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_0) + lpfc_set_features(phba); /* * Discover the port's supported feature set and match it against the @@ -6612,7 +6649,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, - jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); + jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); /* Enable PCIe device Advanced Error Reporting (AER) if configured */ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index cd780c29495a..1f45723a21ed 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -511,6 +511,8 @@ struct lpfc_sli4_hba { uint32_t ue_mask_lo; uint32_t ue_mask_hi; + uint32_t ue_to_sr; + uint32_t ue_to_rp; struct lpfc_register sli_intf; struct lpfc_pc_sli4_params pc_sli4_params; struct msix_entry *msix_entries; From 3aaaa3141796d646052457aaff2a1be7c81aab3a Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:57 -0700 Subject: [PATCH 056/101] lpfc: Correct Buffer credit descriptor values in RDP response Correct Buffer credit descriptor values in RDP response Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 74 +++++++++++++++--------------------- drivers/scsi/lpfc/lpfc_hw.h | 2 +- 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0d05e1a23523..02e3a1fce51e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4719,17 +4719,20 @@ uint32_t lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, struct lpfc_vport *vport) { + uint32_t bbCredit; + desc->tag = cpu_to_be32(RDP_BBC_DESC_TAG); - desc->bbc_info.port_bbc = cpu_to_be32( - vport->fc_sparam.cmn.bbCreditMsb | - vport->fc_sparam.cmn.bbCreditlsb << 8); - if (vport->phba->fc_topology != LPFC_TOPOLOGY_LOOP) - desc->bbc_info.attached_port_bbc = cpu_to_be32( - vport->phba->fc_fabparam.cmn.bbCreditMsb | - vport->phba->fc_fabparam.cmn.bbCreditlsb << 8); - else + bbCredit = vport->fc_sparam.cmn.bbCreditLsb | + (vport->fc_sparam.cmn.bbCreditMsb << 8); + desc->bbc_info.port_bbc = cpu_to_be32(bbCredit); + if (vport->phba->fc_topology != LPFC_TOPOLOGY_LOOP) { + bbCredit = vport->phba->fc_fabparam.cmn.bbCreditLsb | + (vport->phba->fc_fabparam.cmn.bbCreditMsb << 8); + desc->bbc_info.attached_port_bbc = cpu_to_be32(bbCredit); + } else { desc->bbc_info.attached_port_bbc = 0; + } desc->bbc_info.rtt = 0; desc->length = cpu_to_be32(sizeof(desc->bbc_info)); @@ -4745,13 +4748,10 @@ lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); - desc->oed_info.hi_alarm = - cpu_to_be16(page_a2[SSF_TEMP_HIGH_ALARM]); - desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_TEMP_LOW_ALARM]); - desc->oed_info.hi_warning = - cpu_to_be16(page_a2[SSF_TEMP_HIGH_WARNING]); - desc->oed_info.lo_warning = - cpu_to_be16(page_a2[SSF_TEMP_LOW_WARNING]); + desc->oed_info.hi_alarm = page_a2[SSF_TEMP_HIGH_ALARM]; + desc->oed_info.lo_alarm = page_a2[SSF_TEMP_LOW_ALARM]; + desc->oed_info.hi_warning = page_a2[SSF_TEMP_HIGH_WARNING]; + desc->oed_info.lo_warning = page_a2[SSF_TEMP_LOW_WARNING]; if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TEMPERATURE) flags |= RDP_OET_HIGH_ALARM; @@ -4777,13 +4777,10 @@ lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); - desc->oed_info.hi_alarm = - cpu_to_be16(page_a2[SSF_VOLTAGE_HIGH_ALARM]); - desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_VOLTAGE_LOW_ALARM]); - desc->oed_info.hi_warning = - cpu_to_be16(page_a2[SSF_VOLTAGE_HIGH_WARNING]); - desc->oed_info.lo_warning = - cpu_to_be16(page_a2[SSF_VOLTAGE_LOW_WARNING]); + desc->oed_info.hi_alarm = page_a2[SSF_VOLTAGE_HIGH_ALARM]; + desc->oed_info.lo_alarm = page_a2[SSF_VOLTAGE_LOW_ALARM]; + desc->oed_info.hi_warning = page_a2[SSF_VOLTAGE_HIGH_WARNING]; + desc->oed_info.lo_warning = page_a2[SSF_VOLTAGE_LOW_WARNING]; if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_VOLTAGE) flags |= RDP_OET_HIGH_ALARM; @@ -4809,13 +4806,10 @@ lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); - desc->oed_info.hi_alarm = - cpu_to_be16(page_a2[SSF_BIAS_HIGH_ALARM]); - desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_BIAS_LOW_ALARM]); - desc->oed_info.hi_warning = - cpu_to_be16(page_a2[SSF_BIAS_HIGH_WARNING]); - desc->oed_info.lo_warning = - cpu_to_be16(page_a2[SSF_BIAS_LOW_WARNING]); + desc->oed_info.hi_alarm = page_a2[SSF_BIAS_HIGH_ALARM]; + desc->oed_info.lo_alarm = page_a2[SSF_BIAS_LOW_ALARM]; + desc->oed_info.hi_warning = page_a2[SSF_BIAS_HIGH_WARNING]; + desc->oed_info.lo_warning = page_a2[SSF_BIAS_LOW_WARNING]; if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXBIAS) flags |= RDP_OET_HIGH_ALARM; @@ -4841,13 +4835,10 @@ lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); - desc->oed_info.hi_alarm = - cpu_to_be16(page_a2[SSF_TXPOWER_HIGH_ALARM]); - desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_TXPOWER_LOW_ALARM]); - desc->oed_info.hi_warning = - cpu_to_be16(page_a2[SSF_TXPOWER_HIGH_WARNING]); - desc->oed_info.lo_warning = - cpu_to_be16(page_a2[SSF_TXPOWER_LOW_WARNING]); + desc->oed_info.hi_alarm = page_a2[SSF_TXPOWER_HIGH_ALARM]; + desc->oed_info.lo_alarm = page_a2[SSF_TXPOWER_LOW_ALARM]; + desc->oed_info.hi_warning = page_a2[SSF_TXPOWER_HIGH_WARNING]; + desc->oed_info.lo_warning = page_a2[SSF_TXPOWER_LOW_WARNING]; if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXPOWER) flags |= RDP_OET_HIGH_ALARM; @@ -4874,13 +4865,10 @@ lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, desc->tag = cpu_to_be32(RDP_OED_DESC_TAG); - desc->oed_info.hi_alarm = - cpu_to_be16(page_a2[SSF_RXPOWER_HIGH_ALARM]); - desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_RXPOWER_LOW_ALARM]); - desc->oed_info.hi_warning = - cpu_to_be16(page_a2[SSF_RXPOWER_HIGH_WARNING]); - desc->oed_info.lo_warning = - cpu_to_be16(page_a2[SSF_RXPOWER_LOW_WARNING]); + desc->oed_info.hi_alarm = page_a2[SSF_RXPOWER_HIGH_ALARM]; + desc->oed_info.lo_alarm = page_a2[SSF_RXPOWER_LOW_ALARM]; + desc->oed_info.hi_warning = page_a2[SSF_RXPOWER_HIGH_WARNING]; + desc->oed_info.lo_warning = page_a2[SSF_RXPOWER_LOW_WARNING]; if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_RXPOWER) flags |= RDP_OET_HIGH_ALARM; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 829a114d505a..c99c2b3ff430 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -346,7 +346,7 @@ struct csp { uint8_t fcphHigh; /* FC Word 0, byte 0 */ uint8_t fcphLow; uint8_t bbCreditMsb; - uint8_t bbCreditlsb; /* FC Word 0, byte 3 */ + uint8_t bbCreditLsb; /* FC Word 0, byte 3 */ /* * Word 1 Bit 31 in common service parameter is overloaded. From 7d9333139ec0dd7fd1ffa69ad4ab4bf701481ac9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:58 -0700 Subject: [PATCH 057/101] lpfc: Reject RDP ELS if port has no login Reject RDP ELS if port has no login Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 02e3a1fce51e..861270edd84a 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5243,6 +5243,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, be32_to_cpu(rdp_req->nport_id_desc.nport_id), be32_to_cpu(rdp_req->nport_id_desc.length)); + if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED) && + !phba->cfg_enable_SmartSAN) { + rjt_err = LSRJT_UNABLE_TPC; + rjt_expl = LSEXP_PORT_LOGIN_REQ; + goto error; + } if (sizeof(struct fc_rdp_nport_desc) != be32_to_cpu(rdp_req->rdp_des_length)) goto rjt_logerr; From 08dcd4cf3be26024ade20ff7c9f436a2cff83792 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:35:59 -0700 Subject: [PATCH 058/101] lpfc: Add sysfs proc_name support Add sysfs proc_name support Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3bd0be6277b3..12b8e82529fd 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5886,6 +5886,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct scsi_host_template lpfc_template_s3 = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, + .proc_name = LPFC_DRIVER_NAME, .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, @@ -5910,6 +5911,7 @@ struct scsi_host_template lpfc_template_s3 = { struct scsi_host_template lpfc_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, + .proc_name = LPFC_DRIVER_NAME, .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, @@ -5935,6 +5937,7 @@ struct scsi_host_template lpfc_template = { struct scsi_host_template lpfc_vport_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, + .proc_name = LPFC_DRIVER_NAME, .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, From 7bdedb34a0ac1a4b30224c6945eaaebc6fae779a Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:00 -0700 Subject: [PATCH 059/101] lpfc: Add MDS Diagnostics Support Add MDS Diagnostics Support Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 4 ++- drivers/scsi/lpfc/lpfc_attr.c | 10 ++++++ drivers/scsi/lpfc/lpfc_els.c | 7 ++++ drivers/scsi/lpfc/lpfc_hw4.h | 14 +++++++- drivers/scsi/lpfc/lpfc_init.c | 28 +++++++++++++++ drivers/scsi/lpfc/lpfc_sli.c | 65 ++++++++++++++++++++++------------- 6 files changed, 103 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 64d6e3399a68..69da16d63a01 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -695,7 +695,8 @@ struct lpfc_hba { uint8_t wwnn[8]; uint8_t wwpn[8]; uint32_t RandomData[7]; - uint32_t fcp_embed_io; + uint8_t fcp_embed_io; + uint8_t mds_diags_support; /* HBA Config Parameters */ uint32_t cfg_ack0; @@ -760,6 +761,7 @@ struct lpfc_hba { #define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */ #define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */ uint32_t cfg_enable_SmartSAN; + uint32_t cfg_enable_mds_diags; lpfc_vpd_t vpd; /* vital product data */ struct pci_dev *pcidev; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index cfec2eca4dd3..cde7da6af2ea 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4780,6 +4780,14 @@ LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, "Max Protection Scatter Gather Segment Count"); +/* + * lpfc_enable_mds_diags: Enable MDS Diagnostics + * 0 = MDS Diagnostics disabled (default) + * 1 = MDS Diagnostics enabled + * Value range is [0,1]. Default value is 0. + */ +LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); + struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_bg_info, &dev_attr_bg_guard_err, @@ -4876,6 +4884,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_sriov_hw_max_virtfn, &dev_attr_protocol, &dev_attr_lpfc_xlane_supported, + &dev_attr_lpfc_enable_mds_diags, NULL, }; @@ -5867,6 +5876,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); phba->cfg_enable_dss = 1; + lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); return; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 861270edd84a..5afbf4d06d53 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3299,6 +3299,12 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, FC_VPORT_FABRIC_REJ_WWN); } break; + case LSRJT_VENDOR_UNIQUE: + if ((stat.un.b.vendorUnique == 0x45) && + (cmd == ELS_CMD_FLOGI)) { + goto out_retry; + } + break; } break; @@ -3344,6 +3350,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((vport->load_flag & FC_UNLOADING) != 0) retry = 0; +out_retry: if (retry) { if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_FDISC)) { /* Stop retrying PLOGI and FDISC if in FCF discovery */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8738b3dc87f1..ee8022737591 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2888,9 +2888,13 @@ struct lpfc_sli4_parameters { #define cfg_ext_embed_cb_SHIFT 0 #define cfg_ext_embed_cb_MASK 0x00000001 #define cfg_ext_embed_cb_WORD word19 +#define cfg_mds_diags_SHIFT 1 +#define cfg_mds_diags_MASK 0x00000001 +#define cfg_mds_diags_WORD word19 }; -#define LPFC_SET_UE_RECOVERY 0x10 +#define LPFC_SET_UE_RECOVERY 0x10 +#define LPFC_SET_MDS_DIAGS 0x11 struct lpfc_mbx_set_feature { struct mbox_header header; uint32_t feature; @@ -2899,6 +2903,12 @@ struct lpfc_mbx_set_feature { #define lpfc_mbx_set_feature_UER_SHIFT 0 #define lpfc_mbx_set_feature_UER_MASK 0x00000001 #define lpfc_mbx_set_feature_UER_WORD word6 +#define lpfc_mbx_set_feature_mds_SHIFT 0 +#define lpfc_mbx_set_feature_mds_MASK 0x00000001 +#define lpfc_mbx_set_feature_mds_WORD word6 +#define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT 1 +#define lpfc_mbx_set_feature_mds_deep_loopbk_MASK 0x00000001 +#define lpfc_mbx_set_feature_mds_deep_loopbk_WORD word6 uint32_t word7; #define lpfc_mbx_set_feature_UERP_SHIFT 0 #define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff @@ -3464,6 +3474,8 @@ struct lpfc_acqe_fc_la { #define LPFC_FC_LA_TYPE_LINK_UP 0x1 #define LPFC_FC_LA_TYPE_LINK_DOWN 0x2 #define LPFC_FC_LA_TYPE_NO_HARD_ALPA 0x3 +#define LPFC_FC_LA_TYPE_MDS_LINK_DOWN 0x4 +#define LPFC_FC_LA_TYPE_MDS_LOOPBACK 0x5 #define lpfc_acqe_fc_la_port_type_SHIFT 6 #define lpfc_acqe_fc_la_port_type_MASK 0x00000003 #define lpfc_acqe_fc_la_port_type_WORD word0 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f11e33ee4132..bb514d2262cf 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4040,6 +4040,8 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) { struct lpfc_dmabuf *mp; LPFC_MBOXQ_t *pmb; + MAILBOX_t *mb; + struct lpfc_mbx_read_top *la; int rc; if (bf_get(lpfc_trailer_type, acqe_fc) != @@ -4110,6 +4112,24 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; pmb->vport = phba->pport; + if (phba->sli4_hba.link_state.status != LPFC_FC_LA_TYPE_LINK_UP) { + /* Parse and translate status field */ + mb = &pmb->u.mb; + mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, + (void *)acqe_fc); + + /* Parse and translate link attention fields */ + la = (struct lpfc_mbx_read_top *)&pmb->u.mb.un.varReadTop; + la->eventTag = acqe_fc->event_tag; + bf_set(lpfc_mbx_read_top_att_type, la, + LPFC_FC_LA_TYPE_LINK_DOWN); + + /* Invoke the mailbox command callback function */ + lpfc_mbx_cmpl_read_topology(phba, pmb); + + return; + } + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) goto out_free_dmabuf; @@ -9585,6 +9605,14 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->fcp_embed_io = 1; else phba->fcp_embed_io = 0; + + /* + * Check if the SLI port supports MDS Diagnostics + */ + if (bf_get(cfg_mds_diags, mbx_sli4_parameters)) + phba->mds_diags_support = 1; + else + phba->mds_diags_support = 0; return 0; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index b3a781d38fa8..6eef9720e5c9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5691,37 +5691,35 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) } void -lpfc_set_features(struct lpfc_hba *phba) +lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, + uint32_t feature) { - LPFC_MBOXQ_t *mbox = NULL; uint32_t len; - int rc; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return; len = sizeof(struct lpfc_mbx_set_feature) - sizeof(struct lpfc_sli4_cfg_mhdr); lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, LPFC_MBOX_OPCODE_SET_FEATURES, len, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_set_feature_UER, - &mbox->u.mqe.un.set_feature, 1); - mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY; - mbox->u.mqe.un.set_feature.param_len = 8; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - if (rc != MBX_SUCCESS) { - mempool_free(mbox, phba->mbox_mem_pool); - return; + switch (feature) { + case LPFC_SET_UE_RECOVERY: + bf_set(lpfc_mbx_set_feature_UER, + &mbox->u.mqe.un.set_feature, 1); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY; + mbox->u.mqe.un.set_feature.param_len = 8; + break; + case LPFC_SET_MDS_DIAGS: + bf_set(lpfc_mbx_set_feature_mds, + &mbox->u.mqe.un.set_feature, 1); + bf_set(lpfc_mbx_set_feature_mds_deep_loopbk, + &mbox->u.mqe.un.set_feature, 0); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS; + mbox->u.mqe.un.set_feature.param_len = 8; + break; } - phba->hba_flag |= HBA_RECOVERABLE_UE; - phba->eratt_poll_interval = 1; /* Set 1Sec interval to detect UE */ - phba->sli4_hba.ue_to_sr = bf_get(lpfc_mbx_set_feature_UESR, - &mbox->u.mqe.un.set_feature); - phba->sli4_hba.ue_to_rp = bf_get(lpfc_mbx_set_feature_UERP, - &mbox->u.mqe.un.set_feature); - mempool_free(mbox, phba->mbox_mem_pool); + + return; } /** @@ -6449,8 +6447,29 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_0) - lpfc_set_features(phba); + LPFC_SLI_INTF_IF_TYPE_0) { + lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc == MBX_SUCCESS) { + phba->hba_flag |= HBA_RECOVERABLE_UE; + /* Set 1Sec interval to detect UE */ + phba->eratt_poll_interval = 1; + phba->sli4_hba.ue_to_sr = bf_get( + lpfc_mbx_set_feature_UESR, + &mboxq->u.mqe.un.set_feature); + phba->sli4_hba.ue_to_rp = bf_get( + lpfc_mbx_set_feature_UERP, + &mboxq->u.mqe.un.set_feature); + } + } + + if (phba->cfg_enable_mds_diags && phba->mds_diags_support) { + /* Enable MDS Diagnostics only if the SLI Port supports it */ + lpfc_set_features(phba, mboxq, LPFC_SET_MDS_DIAGS); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc != MBX_SUCCESS) + phba->mds_diags_support = 0; + } /* * Discover the port's supported feature set and match it against the From 4597663fabf16645e2af8f02b9d7ba66110588b6 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:01 -0700 Subject: [PATCH 060/101] lpfc: Fix SLI mode 2 config failure Fix SLI mode 2 config failure Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 6eef9720e5c9..b1ddbaac1c79 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4696,6 +4696,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) "Not supported by adapter.\n"); if (rc && mode != 2) rc = lpfc_sli_config_port(phba, 2); + else if (rc && mode == 2) + rc = lpfc_sli_config_port(phba, 3); if (rc) goto lpfc_sli_hba_setup_error; From a1cadfeffac70a1ed77b45a8f93b92b9cb501d94 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:02 -0700 Subject: [PATCH 061/101] lpfc: Correct FCOE discovery to avoid loss of storage devices after system reboot Correct FCOE discovery to avoid loss of storage devices after system reboot Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bb514d2262cf..8d940ed2b504 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4484,7 +4484,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, * the corresponding FCF bit in the roundrobin bitmap. */ spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { + if ((phba->fcf.fcf_flag & FCF_DISCOVERY) && + (phba->fcf.current_rec.fcf_indx != acqe_fip->index)) { spin_unlock_irq(&phba->hbalock); /* Update FLOGI FCF failover eligible FCF bmask */ lpfc_sli4_fcf_rr_index_clear(phba, acqe_fip->index); From 12f4445733c516648ab0b013314a83467876ac2f Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:03 -0700 Subject: [PATCH 062/101] lpfc: Re-organize source for easier device-id management Re-organize source for easier device-id management Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ids.h | 122 ++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_init.c | 101 +--------------------------- 2 files changed, 123 insertions(+), 100 deletions(-) create mode 100644 drivers/scsi/lpfc/lpfc_ids.h diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h new file mode 100644 index 000000000000..5733feafe25f --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_ids.h @@ -0,0 +1,122 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +#include + +const struct pci_device_id lpfc_id_table[] = { + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0 } +}; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 8d940ed2b504..6e11574ac6f2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -52,6 +52,7 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" +#include "lpfc_ids.h" char *_dump_buf_data; unsigned long _dump_buf_data_order; @@ -11385,106 +11386,6 @@ lpfc_fof_queue_destroy(struct lpfc_hba *phba) return 0; } -static struct pci_device_id lpfc_id_table[] = { - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - { 0 } -}; - MODULE_DEVICE_TABLE(pci, lpfc_id_table); static const struct pci_error_handlers lpfc_err_handler = { From 5b1993dedfdc131ff095c0c079ef106aed3fe9ac Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:04 -0700 Subject: [PATCH 063/101] lpfc: Correct RDP response Revision location Correct RDP response Revision location Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c99c2b3ff430..822654322e67 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1239,8 +1239,8 @@ struct fc_rdp_opd_sfp_info { uint8_t vendor_name[16]; uint8_t model_number[16]; uint8_t serial_number[16]; - uint8_t reserved[2]; uint8_t revision[2]; + uint8_t reserved[2]; uint8_t date[8]; }; From c92c841cc72ae7eb665fb9ea2a1c991e214c3807 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:05 -0700 Subject: [PATCH 064/101] lpfc: Add support for XLane LUN priority Add support for XLane LUN priority Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 89 ++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 9 +++- drivers/scsi/lpfc/lpfc_scsi.h | 1 + drivers/scsi/lpfc/lpfc_sli.c | 21 ++++++--- drivers/scsi/lpfc/lpfc_sli.h | 1 + 7 files changed, 104 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 69da16d63a01..40e069c76091 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -743,6 +743,7 @@ struct lpfc_hba { #define OAS_FIND_ANY_VPORT 0x01 #define OAS_FIND_ANY_TARGET 0x02 #define OAS_LUN_VALID 0x04 + uint32_t cfg_oas_priority; uint32_t cfg_XLanePriority; uint32_t cfg_enable_bg; uint32_t cfg_hostmem_hgp; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index cde7da6af2ea..a75404ae4fc1 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2400,6 +2400,69 @@ lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(lpfc_xlane_tgt, S_IRUGO | S_IWUSR, lpfc_oas_tgt_show, lpfc_oas_tgt_store); +/** + * lpfc_oas_priority_show - Return wwpn of target whose luns maybe enabled for + * Optimized Access Storage (OAS) operations. + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: buffer for passing information. + * + * Returns: + * value of count + **/ +static ssize_t +lpfc_oas_priority_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority); +} + +/** + * lpfc_oas_priority_store - Store wwpn of target whose luns maybe enabled for + * Optimized Access Storage (OAS) operations. + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: buffer for passing information. + * @count: Size of the data buffer. + * + * Returns: + * -EINVAL count is invalid, invalid wwpn byte invalid + * -EPERM oas is not supported by hba + * value of count on success + **/ +static ssize_t +lpfc_oas_priority_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + unsigned int cnt = count; + unsigned long val; + int ret; + + if (!phba->cfg_fof) + return -EPERM; + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + ret = kstrtoul(buf, 0, &val); + if (ret || (val > 0x7f)) + return -EINVAL; + + if (val) + phba->cfg_oas_priority = (uint8_t)val; + else + phba->cfg_oas_priority = phba->cfg_XLanePriority; + return count; +} +static DEVICE_ATTR(lpfc_xlane_priority, S_IRUGO | S_IWUSR, + lpfc_oas_priority_show, lpfc_oas_priority_store); + /** * lpfc_oas_vpt_show - Return wwpn of vport whose targets maybe enabled * for Optimized Access Storage (OAS) operations. @@ -2462,6 +2525,7 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr, else phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT; phba->cfg_oas_flags &= ~OAS_LUN_VALID; + phba->cfg_oas_priority = phba->cfg_XLanePriority; phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN; return count; } @@ -2524,7 +2588,6 @@ lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr, return -EINVAL; phba->cfg_oas_lun_state = val; - return strlen(buf); } static DEVICE_ATTR(lpfc_xlane_lun_state, S_IRUGO | S_IWUSR, @@ -2572,7 +2635,8 @@ static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO, */ static size_t lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], - uint8_t tgt_wwpn[], uint64_t lun, uint32_t oas_state) + uint8_t tgt_wwpn[], uint64_t lun, + uint32_t oas_state, uint8_t pri) { int rc = 0; @@ -2582,7 +2646,8 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], if (oas_state) { if (!lpfc_enable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, - (struct lpfc_name *)tgt_wwpn, lun)) + (struct lpfc_name *)tgt_wwpn, + lun, pri)) rc = -ENOMEM; } else { lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, @@ -2648,13 +2713,13 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], static ssize_t lpfc_oas_lun_state_change(struct lpfc_hba *phba, uint8_t vpt_wwpn[], uint8_t tgt_wwpn[], uint64_t lun, - uint32_t oas_state) + uint32_t oas_state, uint8_t pri) { int rc; rc = lpfc_oas_lun_state_set(phba, vpt_wwpn, tgt_wwpn, lun, - oas_state); + oas_state, pri); return rc; } @@ -2744,16 +2809,16 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, return -EINVAL; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3372 Try to set vport 0x%llx target 0x%llx lun:%lld " - "with oas set to %d\n", + "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx " + "priority 0x%x with oas state %d\n", wwn_to_u64(phba->cfg_oas_vpt_wwpn), wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun, - phba->cfg_oas_lun_state); + phba->cfg_oas_priority, phba->cfg_oas_lun_state); rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn, - phba->cfg_oas_tgt_wwpn, scsi_lun, - phba->cfg_oas_lun_state); - + phba->cfg_oas_tgt_wwpn, scsi_lun, + phba->cfg_oas_lun_state, + phba->cfg_oas_priority); if (rc) return rc; @@ -4865,6 +4930,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_xlane_vpt, &dev_attr_lpfc_xlane_lun_state, &dev_attr_lpfc_xlane_lun_status, + &dev_attr_lpfc_xlane_priority, &dev_attr_lpfc_sg_seg_cnt, &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, @@ -5858,6 +5924,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_oas_lun_state = 0; phba->cfg_oas_lun_status = 0; phba->cfg_oas_flags = 0; + phba->cfg_oas_priority = 0; lpfc_enable_bg_init(phba, lpfc_enable_bg); if (phba->sli_rev == LPFC_SLI_REV4) phba->cfg_poll = 0; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 4e55b35180a4..bc0e2f197ff5 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -492,7 +492,7 @@ struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t); bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *, - struct lpfc_name *, uint64_t); + struct lpfc_name *, uint64_t, uint8_t); bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t); bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *, diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 12b8e82529fd..3f33fd6b1b6f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3335,8 +3335,11 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) * OAS, set the oas iocb related flags. */ if ((phba->cfg_fof) && ((struct lpfc_device_data *) - scsi_cmnd->device->hostdata)->oas_enabled) + scsi_cmnd->device->hostdata)->oas_enabled) { lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); + lpfc_cmd->cur_iocbq.priority = ((struct lpfc_device_data *) + scsi_cmnd->device->hostdata)->priority; + } return 0; } @@ -5607,6 +5610,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, sizeof(struct lpfc_name)); lun_info->device_id.lun = lun; lun_info->oas_enabled = false; + lun_info->priority = phba->cfg_XLanePriority; lun_info->available = false; return lun_info; } @@ -5798,7 +5802,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, **/ bool lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, - struct lpfc_name *target_wwpn, uint64_t lun) + struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri) { struct lpfc_device_data *lun_info; @@ -5825,6 +5829,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, false); if (lun_info) { lun_info->oas_enabled = true; + lun_info->priority = pri; lun_info->available = false; list_add_tail(&lun_info->listentry, &phba->luns); spin_unlock_irqrestore(&phba->devicelock, flags); diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 18b9260ccfac..46c090bd053b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -51,6 +51,7 @@ struct lpfc_device_data { struct list_head listentry; struct lpfc_rport_data *rport_data; struct lpfc_device_id device_id; + uint8_t priority; bool oas_enabled; bool available; }; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index b1ddbaac1c79..53ed6c534f82 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -8441,8 +8441,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1); if (iocbq->iocb_flag & LPFC_IO_OAS) { bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1); - if (phba->cfg_XLanePriority) { - bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); + if (iocbq->priority) { + bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, + (iocbq->priority << 1)); + } else { bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, (phba->cfg_XLanePriority << 1)); } @@ -8497,8 +8500,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); if (iocbq->iocb_flag & LPFC_IO_OAS) { bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1); - if (phba->cfg_XLanePriority) { - bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1); + if (iocbq->priority) { + bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com, + (iocbq->priority << 1)); + } else { bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com, (phba->cfg_XLanePriority << 1)); } @@ -8552,8 +8558,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->iocb.ulpFCP2Rcvy); if (iocbq->iocb_flag & LPFC_IO_OAS) { bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1); - if (phba->cfg_XLanePriority) { - bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1); + if (iocbq->priority) { + bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com, + (iocbq->priority << 1)); + } else { bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com, (phba->cfg_XLanePriority << 1)); } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 7fe99ff80846..b33dbd323694 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -57,6 +57,7 @@ struct lpfc_iocbq { struct lpfc_cq_event cq_event; IOCB_t iocb; /* IOCB cmd */ + uint8_t priority; /* OAS priority */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ uint32_t iocb_flag; #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ From 0e916ee71d2f0453dbfe402cd8ca24f9668518ad Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:06 -0700 Subject: [PATCH 065/101] lpfc: Correct Port reset resulting in FC port going offline Correct Port reset resulting in FC port going offline Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6e11574ac6f2..f4b3548f101a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1595,9 +1595,10 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, * ready before performing reset. */ rc = lpfc_sli4_pdev_status_reg_wait(phba); - if (!rc) + if (rc) return rc; } + /* need reset: attempt for port recovery */ if (en_rn_msg) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, From 458c083e83ed2f8e446cf1a38dd21996cebe6da0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:07 -0700 Subject: [PATCH 066/101] lpfc: Remove global lpfc_enable_npiv attribute in leiu of per-hba lpfc_enable_npiv Remove global lpfc_enable_npiv attribute in leiu of per-hba lpfc_enable_npiv Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 8 ++------ drivers/scsi/lpfc/lpfc_crtn.h | 1 - drivers/scsi/lpfc/lpfc_init.c | 24 +++++++++--------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index a75404ae4fc1..25d91a86e4a6 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2844,12 +2844,8 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" " 2 - select SLI-2 even on SLI-3 capable HBAs," " 3 - select SLI-3"); -int lpfc_enable_npiv = 1; -module_param(lpfc_enable_npiv, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality"); -lpfc_param_show(enable_npiv); -lpfc_param_init(enable_npiv, 1, 0, 1); -static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); +LPFC_ATTR_R(enable_npiv, 1, 0, 1, + "Enable NPIV functionality"); LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2, "FCF Fast failover=1 Priority failover=2"); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bc0e2f197ff5..b8a2ddc49e50 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -360,7 +360,6 @@ extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; extern int lpfc_sli_mode; -extern int lpfc_enable_npiv; extern int lpfc_delay_discovery; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f4b3548f101a..adf61b43eb70 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11441,21 +11441,17 @@ lpfc_init(void) printk(KERN_ERR "Could not register lpfcmgmt device, " "misc_register returned with status %d", error); - if (lpfc_enable_npiv) { - lpfc_transport_functions.vport_create = lpfc_vport_create; - lpfc_transport_functions.vport_delete = lpfc_vport_delete; - } + lpfc_transport_functions.vport_create = lpfc_vport_create; + lpfc_transport_functions.vport_delete = lpfc_vport_delete; lpfc_transport_template = fc_attach_transport(&lpfc_transport_functions); if (lpfc_transport_template == NULL) return -ENOMEM; - if (lpfc_enable_npiv) { - lpfc_vport_transport_template = - fc_attach_transport(&lpfc_vport_transport_functions); - if (lpfc_vport_transport_template == NULL) { - fc_release_transport(lpfc_transport_template); - return -ENOMEM; - } + lpfc_vport_transport_template = + fc_attach_transport(&lpfc_vport_transport_functions); + if (lpfc_vport_transport_template == NULL) { + fc_release_transport(lpfc_transport_template); + return -ENOMEM; } /* Initialize in case vector mapping is needed */ @@ -11467,8 +11463,7 @@ lpfc_init(void) error = pci_register_driver(&lpfc_driver); if (error) { fc_release_transport(lpfc_transport_template); - if (lpfc_enable_npiv) - fc_release_transport(lpfc_vport_transport_template); + fc_release_transport(lpfc_vport_transport_template); } return error; @@ -11487,8 +11482,7 @@ lpfc_exit(void) misc_deregister(&lpfc_mgmt_dev); pci_unregister_driver(&lpfc_driver); fc_release_transport(lpfc_transport_template); - if (lpfc_enable_npiv) - fc_release_transport(lpfc_vport_transport_template); + fc_release_transport(lpfc_vport_transport_template); if (_dump_buf_data) { printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for " "_dump_buf_data at 0x%p\n", From 8eb8b960fd0593baaddd1c01cbff6b85c5056ccf Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:08 -0700 Subject: [PATCH 067/101] lpfc: Remove global lpfc_delay_discovery attribute in leiu of per-hba lpfc_delay_discovery Remove global lpfc_delay_discovery attribute in leiu of per-hba lpfc_delay_discovery Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 8 +++----- drivers/scsi/lpfc/lpfc_crtn.h | 1 - drivers/scsi/lpfc/lpfc_els.c | 3 ++- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 40e069c76091..82d7b115b650 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -754,6 +754,7 @@ struct lpfc_hba { uint32_t cfg_iocb_cnt; uint32_t cfg_suppress_link_up; uint32_t cfg_rrq_xri_bitmap_sz; + uint32_t cfg_delay_discovery; #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ #define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 25d91a86e4a6..f5abcea49730 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4815,11 +4815,8 @@ MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type"); * accept and FCID/Fabric name/Fabric portname is changed. * Default value is 0. */ -int lpfc_delay_discovery; -module_param(lpfc_delay_discovery, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_delay_discovery, - "Delay NPort discovery when Clean Address bit is cleared. " - "Allowed values: 0,1."); +LPFC_ATTR(delay_discovery, 0, 0, 1, + "Delay NPort discovery when Clean Address bit is cleared."); /* * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count @@ -5938,6 +5935,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade); lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); + lpfc_delay_discovery_init(phba, lpfc_delay_discovery); phba->cfg_enable_dss = 1; lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); return; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b8a2ddc49e50..9f075db51099 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -360,7 +360,6 @@ extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; extern int lpfc_sli_mode; -extern int lpfc_delay_discovery; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 5afbf4d06d53..c0af32f24954 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -594,6 +594,7 @@ static uint8_t lpfc_check_clean_addr_bit(struct lpfc_vport *vport, struct serv_parm *sp) { + struct lpfc_hba *phba = vport->phba; uint8_t fabric_param_changed = 0; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -615,7 +616,7 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport, * - lpfc_delay_discovery module parameter is set. */ if (fabric_param_changed && !sp->cmn.clean_address_bit && - (vport->fc_prevDID || lpfc_delay_discovery)) { + (vport->fc_prevDID || phba->cfg_delay_discovery)) { spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_DISC_DELAYED; spin_unlock_irq(shost->host_lock); From 12247e8101eacfda790a14944c34bdccb6e90d6b Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:09 -0700 Subject: [PATCH 068/101] lpfc: Remove global lpfc_sli_mode attribute in leiu of per-hba lpfc_sli_mode Remove global lpfc_sli_mode attribute in leiu of per-hba lpfc_sli_mode Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_crtn.h | 1 - drivers/scsi/lpfc/lpfc_sli.c | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 82d7b115b650..4d9f1b189659 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -755,6 +755,7 @@ struct lpfc_hba { uint32_t cfg_suppress_link_up; uint32_t cfg_rrq_xri_bitmap_sz; uint32_t cfg_delay_discovery; + uint32_t cfg_sli_mode; #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ #define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f5abcea49730..07d80336dfc0 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2837,12 +2837,11 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:" static DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR, lpfc_poll_show, lpfc_poll_store); -int lpfc_sli_mode = 0; -module_param(lpfc_sli_mode, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" - " 0 - auto (SLI-3 if supported)," - " 2 - select SLI-2 even on SLI-3 capable HBAs," - " 3 - select SLI-3"); +LPFC_ATTR(sli_mode, 0, 0, 3, + "SLI mode selector:" + " 0 - auto (SLI-3 if supported)," + " 2 - select SLI-2 even on SLI-3 capable HBAs," + " 3 - select SLI-3"); LPFC_ATTR_R(enable_npiv, 1, 0, 1, "Enable NPIV functionality"); @@ -5936,6 +5935,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); lpfc_delay_discovery_init(phba, lpfc_delay_discovery); + lpfc_sli_mode_init(phba, lpfc_sli_mode); phba->cfg_enable_dss = 1; lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); return; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 9f075db51099..3a5a02e36950 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -359,7 +359,6 @@ extern struct scsi_host_template lpfc_template_s3; extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; -extern int lpfc_sli_mode; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 53ed6c534f82..c8fd0a349eba 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4665,13 +4665,13 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) int mode = 3, i; int longs; - switch (lpfc_sli_mode) { + switch (phba->cfg_sli_mode) { case 2: if (phba->cfg_enable_npiv) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1824 NPIV enabled: Override lpfc_sli_mode " + "1824 NPIV enabled: Override sli_mode " "parameter (%d) to auto (0).\n", - lpfc_sli_mode); + phba->cfg_sli_mode); break; } mode = 2; @@ -4681,8 +4681,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) break; default: lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1819 Unrecognized lpfc_sli_mode " - "parameter: %d.\n", lpfc_sli_mode); + "1819 Unrecognized sli_mode parameter: %d.\n", + phba->cfg_sli_mode); break; } @@ -4690,7 +4690,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli_config_port(phba, mode); - if (rc && lpfc_sli_mode == 3) + if (rc && phba->cfg_sli_mode == 3) lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, "1820 Unable to select SLI-3. " "Not supported by adapter.\n"); From 93dd1911cf4913321d91aa9c525f5f8149f90fee Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:10 -0700 Subject: [PATCH 069/101] lpfc: Re-organize source for easier driver attribute management Re-organize source for easier driver attribute management Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 97 +--------------------------- drivers/scsi/lpfc/lpfc_attr.h | 116 ++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 96 deletions(-) create mode 100644 drivers/scsi/lpfc/lpfc_attr.h diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 07d80336dfc0..6793df86a425 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -48,6 +48,7 @@ #include "lpfc_compat.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" +#include "lpfc_attr.h" #define LPFC_DEF_DEVLOSS_TMO 30 #define LPFC_MIN_DEVLOSS_TMO 1 @@ -1939,102 +1940,6 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ } -#define LPFC_ATTR(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_init(name, defval, minval, maxval) - -#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -lpfc_param_set(name, defval, minval, maxval)\ -lpfc_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_hex_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_hex_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -lpfc_param_set(name, defval, minval, maxval)\ -lpfc_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_init(name, defval, minval, maxval) - -#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_VPORT_ULL_ATTR_R(name, defval, minval, maxval, desc) \ -static uint64_t lpfc_##name = defval;\ -module_param(lpfc_##name, ullong, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -lpfc_vport_param_set(name, defval, minval, maxval)\ -lpfc_vport_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_hex_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_hex_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -lpfc_vport_param_set(name, defval, minval, maxval)\ -lpfc_vport_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL); static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL); static DEVICE_ATTR(bg_apptag_err, S_IRUGO, lpfc_bg_apptag_err_show, NULL); diff --git a/drivers/scsi/lpfc/lpfc_attr.h b/drivers/scsi/lpfc/lpfc_attr.h new file mode 100644 index 000000000000..b2bd28e965fa --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_attr.h @@ -0,0 +1,116 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +#define LPFC_ATTR(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_init(name, defval, minval, maxval) + +#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL) + +#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL) + +#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_init(name, defval, minval, maxval) + +#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ULL_ATTR_R(name, defval, minval, maxval, desc) \ +static uint64_t lpfc_##name = defval;\ +module_param(lpfc_##name, ullong, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +lpfc_vport_param_set(name, defval, minval, maxval)\ +lpfc_vport_param_store(name)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_hex_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ +static uint lpfc_##name = defval;\ +module_param(lpfc_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_vport_param_hex_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +lpfc_vport_param_set(name, defval, minval, maxval)\ +lpfc_vport_param_store(name)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) From 115a4124bae6697b375e150deaed3a4ffc6580e1 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:11 -0700 Subject: [PATCH 070/101] lpfc: Correct issue with ioremap() call on 32bit kernel Correct issue with ioremap() call on 32bit kernel Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 4d9f1b189659..b484859464f6 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -785,9 +785,9 @@ struct lpfc_hba { atomic_t fcp_qidx; /* next work queue to post work to */ - unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ - unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */ - unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ + phys_addr_t pci_bar0_map; /* Physical address for PCI BAR0 */ + phys_addr_t pci_bar1_map; /* Physical address for PCI BAR1 */ + phys_addr_t pci_bar2_map; /* Physical address for PCI BAR2 */ void __iomem *slim_memmap_p; /* Kernel memory mapped address for PCI BAR0 */ void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for From a03a4219a4e0b3e53078a2f97fee0b5a4cab2a20 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:12 -0700 Subject: [PATCH 071/101] lpfc: Disable FDMI probing if not connected to a fabric Disable FDMI probing if not connected to a fabric Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index a38816e96654..63e48d4277b0 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1510,6 +1510,10 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport) if (!lpfc_is_link_up(phba)) return; + /* Must be connected to a Fabric */ + if (!(vport->fc_flag & FC_FABRIC)) + return; + if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc)) return; From 51f4ca3c93b2eaf80a182e9fcfa4f9e5706cca12 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:13 -0700 Subject: [PATCH 072/101] lpfc: Copyright updates Copyright updates Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.h | 2 +- drivers/scsi/lpfc/lpfc_sli.h | 2 +- drivers/scsi/lpfc/lpfc_sli4.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 3a5a02e36950..bd7576d452f2 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2015 Emulex. All rights reserved. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3f33fd6b1b6f..a5655d571906 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2015 Emulex. All rights reserved. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 46c090bd053b..8cb80dabada8 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2015 Emulex. All rights reserved. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index b33dbd323694..74227a28bd56 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2015 Emulex. All rights reserved. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 1f45723a21ed..0b88b5703e0f 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2015 Emulex. All rights reserved. * + * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * From 648222d2652d55dccdcf5b734b85c19d2664525e Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 6 Jul 2016 12:36:14 -0700 Subject: [PATCH 073/101] lpfc: Update lpfc version to 11.2.0.0 Update lpfc version to 11.2.0.0 Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index fa0d531bf351..c9bf20eb7223 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 "11.1.0.0." +#define LPFC_DRIVER_VERSION "11.2.0.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From f1d7ce65c9003a8e027a8745adc74b550da3ab16 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:17 -0400 Subject: [PATCH 074/101] qla2xxx: Remove sysfs node fw_dump_template. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 89 --------------------------------- drivers/scsi/qla2xxx/qla_dbg.c | 1 + 2 files changed, 1 insertion(+), 89 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4dc06a13cab8..c9bcd82f08bc 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -146,92 +146,6 @@ static struct bin_attribute sysfs_fw_dump_attr = { .write = qla2x00_sysfs_write_fw_dump, }; -static ssize_t -qla2x00_sysfs_read_fw_dump_template(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - if (!ha->fw_dump_template || !ha->fw_dump_template_len) - return 0; - - ql_dbg(ql_dbg_user, vha, 0x70e2, - "chunk <- off=%llx count=%zx\n", off, count); - return memory_read_from_buffer(buf, count, &off, - ha->fw_dump_template, ha->fw_dump_template_len); -} - -static ssize_t -qla2x00_sysfs_write_fw_dump_template(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - uint32_t size; - - if (off == 0) { - if (ha->fw_dump) - vfree(ha->fw_dump); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - - ha->fw_dump = NULL; - ha->fw_dump_len = 0; - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - - size = qla27xx_fwdt_template_size(buf); - ql_dbg(ql_dbg_user, vha, 0x70d1, - "-> allocating fwdt (%x bytes)...\n", size); - ha->fw_dump_template = vmalloc(size); - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x70d2, - "Failed allocate fwdt (%x bytes).\n", size); - return -ENOMEM; - } - ha->fw_dump_template_len = size; - } - - if (off + count > ha->fw_dump_template_len) { - count = ha->fw_dump_template_len - off; - ql_dbg(ql_dbg_user, vha, 0x70d3, - "chunk -> truncating to %zx bytes.\n", count); - } - - ql_dbg(ql_dbg_user, vha, 0x70d4, - "chunk -> off=%llx count=%zx\n", off, count); - memcpy(ha->fw_dump_template + off, buf, count); - - if (off + count == ha->fw_dump_template_len) { - size = qla27xx_fwdt_calculate_dump_size(vha); - ql_dbg(ql_dbg_user, vha, 0x70d5, - "-> allocating fwdump (%x bytes)...\n", size); - ha->fw_dump = vmalloc(size); - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0x70d6, - "Failed allocate fwdump (%x bytes).\n", size); - return -ENOMEM; - } - ha->fw_dump_len = size; - } - - return count; -} -static struct bin_attribute sysfs_fw_dump_template_attr = { - .attr = { - .name = "fw_dump_template", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_fw_dump_template, - .write = qla2x00_sysfs_write_fw_dump_template, -}; - static ssize_t qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -973,7 +887,6 @@ static struct sysfs_entry { int is4GBp_only; } bin_file_entries[] = { { "fw_dump", &sysfs_fw_dump_attr, }, - { "fw_dump_template", &sysfs_fw_dump_template_attr, 0x27 }, { "nvram", &sysfs_nvram_attr, }, { "optrom", &sysfs_optrom_attr, }, { "optrom_ctl", &sysfs_optrom_ctl_attr, }, @@ -1000,8 +913,6 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) continue; if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw))) continue; - if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw)) - continue; ret = sysfs_create_bin_file(&host->shost_gendev.kobj, iter->attr); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index b64c504ff12f..b985fcbdf79b 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -39,6 +39,7 @@ * | | | 0x70a5-0x70a6 | * | | | 0x70a8,0x70ab | * | | | 0x70ad-0x70ae | + * | | | 0x70d0-0x70d6 | * | | | 0x70d7-0x70db | * | | | 0x70de-0x70df | * | Task Management | 0x803d | 0x8000,0x800b | From ad1ef1777d5f3b605fe07062da2f08689c507014 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:18 -0400 Subject: [PATCH 075/101] qla2xxx: Add ram area DDR for fwdump template entry T262. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_mbx.c | 7 +++++-- drivers/scsi/qla2xxx/qla_tmpl.c | 9 ++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 47f8b9b49bac..7f861474d7b5 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3370,6 +3370,8 @@ struct qla_hw_data { uint32_t fw_shared_ram_start; uint32_t fw_shared_ram_end; + uint32_t fw_ddr_ram_start; + uint32_t fw_ddr_ram_end; uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */ uint8_t fw_seriallink_options[4]; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 968b84613096..9673a0b645ee 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -782,8 +782,9 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) if (IS_FWI2_CAPABLE(ha)) mcp->in_mb |= MBX_17|MBX_16|MBX_15; if (IS_QLA27XX(ha)) - mcp->in_mb |= MBX_23 | MBX_22 | MBX_21 | MBX_20 | MBX_19 | - MBX_18 | MBX_14 | MBX_13 | MBX_11 | MBX_10 | MBX_9 | MBX_8; + mcp->in_mb |= + MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18| + MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8; mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; @@ -842,6 +843,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->pep_version[2] = mcp->mb[14] & 0xff; ha->fw_shared_ram_start = (mcp->mb[19] << 16) | mcp->mb[18]; ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20]; + ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22]; + ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24]; } failed: diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index c3e622524604..36935c9ed669 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -357,6 +357,13 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, ent->t262.start_addr = start; ent->t262.end_addr = end; } + } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) { + start = vha->hw->fw_ddr_ram_start; + end = vha->hw->fw_ddr_ram_end; + if (buf) { + ent->t262.start_addr = start; + ent->t262.end_addr = end; + } } else { ql_dbg(ql_dbg_misc, vha, 0xd022, "%s: unknown area %x\n", __func__, ent->t262.ram_area); @@ -364,7 +371,7 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, goto done; } - if (end < start || end == 0) { + if (end <= start || start == 0 || end == 0) { ql_dbg(ql_dbg_misc, vha, 0xd023, "%s: unusable range (start=%x end=%x)\n", __func__, ent->t262.end_addr, ent->t262.start_addr); From a29b3dd7aa14facc902b40b8b5c4dccbfb2ad7d0 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:19 -0400 Subject: [PATCH 076/101] qla2xxx: Shutdown board on thermal shutdown aen. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_isr.c | 7 +++++++ drivers/scsi/qla2xxx/qla_os.c | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index b985fcbdf79b..0671f07a0974 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -27,7 +27,7 @@ * | | | 0x303a | * | DPC Thread | 0x4023 | 0x4002,0x4013 | * | Async Events | 0x5089 | 0x502b-0x502f | - * | | | 0x505e | + * | | | 0x5047 | * | | | 0x5084,0x5075 | * | | | 0x503d,0x5044 | * | | | 0x507b,0x505f | diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7f861474d7b5..2b7e4f5574bb 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -829,6 +829,7 @@ struct mbx_cmd_32 { #define MBA_FW_RESTART_CMPLT 0x8060 /* Firmware restart complete */ #define MBA_INIT_REQUIRED 0x8061 /* Initialization required */ #define MBA_SHUTDOWN_REQUESTED 0x8062 /* Shutdown Requested */ +#define MBA_TEMPERATURE_ALERT 0x8070 /* Temperature Alert */ #define MBA_DPORT_DIAGNOSTICS 0x8080 /* D-port Diagnostics */ #define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */ #define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ea8641b47c86..a2d7935ffeea 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1158,6 +1158,13 @@ global_port_update: mb[1] == 2 ? "done (error)" : "other"); break; + case MBA_TEMPERATURE_ALERT: + ql_dbg(ql_dbg_async, vha, 0x505e, + "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]); + if (mb[1] == 0x12) + schedule_work(&ha->board_disable); + break; + default: ql_dbg(ql_dbg_async, vha, 0x5057, "Unknown AEN:%04x %04x %04x %04x\n", diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7c0b60ca158f..dc608ce46340 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2901,6 +2901,10 @@ skip_dpc: qlt_add_target(ha, base_vha); clear_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags); + + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + return -ENODEV; + return 0; probe_init_failed: @@ -2947,7 +2951,10 @@ iospace_config_failed: ha = NULL; probe_out: + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + return -ENODEV; return ret; } @@ -5002,6 +5009,9 @@ qla2x00_do_dpc(void *data) "DPC handler waking up, dpc_flags=0x%lx.\n", base_vha->dpc_flags); + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + break; + qla2x00_do_work(base_vha); if (IS_P3P_TYPE(ha)) { From 088d09d465a1a31929b98f3363965c91e8ab4c65 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 6 Jul 2016 11:14:20 -0400 Subject: [PATCH 077/101] qla2xxx: Set FLOGI retry in additional firmware options for P2P (N2N) mode. When VP decoupling enabled, there could be a window where, FLOGI from initiators can be dropped before VP0 is enabled, causing link level recovery. Retry FLOGI to avoid link level recovery. Signed-off-by: Giridhar Malavali Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_init.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 0671f07a0974..907a7acb1639 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -16,7 +16,7 @@ * | | | 0x016e-0x0170 | * | Mailbox commands | 0x1192 | | * | | | | - * | Device Discovery | 0x2016 | 0x2020-0x2022, | + * | Device Discovery | 0x2003 | 0x2016 | * | | | 0x2011-0x2012, | * | | | 0x2099-0x20a4 | * | Queue Command and IO tracing | 0x3074 | 0x300b | diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c56cdb35f3ed..a3685b683688 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2053,6 +2053,14 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha) if (IS_QLA6312(ha)) ha->fw_options[2] |= BIT_13; + /* Set Retry FLOGI in case of P2P connection */ + if (ha->operating_mode == P2P) { + ha->fw_options[2] |= BIT_3; + ql_dbg(ql_dbg_disc, vha, 0x2100, + "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n", + __func__, ha->fw_options[2]); + } + /* Update firmware options. */ qla2x00_set_fw_options(vha, ha->fw_options); } @@ -2070,6 +2078,14 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) if (ql2xfwholdabts) ha->fw_options[3] |= BIT_12; + /* Set Retry FLOGI in case of P2P connection */ + if (ha->operating_mode == P2P) { + ha->fw_options[2] |= BIT_3; + ql_dbg(ql_dbg_disc, vha, 0x2101, + "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n", + __func__, ha->fw_options[2]); + } + /* Update Serial Link options. */ if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0) return; @@ -6513,6 +6529,14 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha) if (ql2xfwholdabts) ha->fw_options[3] |= BIT_12; + /* Set Retry FLOGI in case of P2P connection */ + if (ha->operating_mode == P2P) { + ha->fw_options[2] |= BIT_3; + ql_dbg(ql_dbg_disc, vha, 0x2103, + "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n", + __func__, ha->fw_options[2]); + } + if (!ql2xetsenable) goto out; From a2b3e01da730a87023c66d1c104c43848dbba847 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:21 -0400 Subject: [PATCH 078/101] qla2xxx: Add module parameter alternate/short names. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index dc608ce46340..f1a2394a99e5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -80,6 +80,7 @@ MODULE_PARM_DESC(ql2xallocfwdump, int ql2xextended_error_logging; module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); +module_param_named(logging, ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xextended_error_logging, "Option to enable extended error logging,\n" "\t\tDefault is 0 - no logging. 0x40000000 - Module Init & Probe.\n" @@ -106,6 +107,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd, int ql2xfdmienable=1; module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR); +module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xfdmienable, "Enables FDMI registrations. " "0 - no FDMI. Default is 1 - perform FDMI."); @@ -157,6 +159,7 @@ MODULE_PARM_DESC(ql2xmultique_tag, int ql2xfwloadbin; module_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR); +module_param_named(fwload, ql2xfwloadbin, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xfwloadbin, "Option to specify location from which to load ISP firmware:.\n" " 2 -- load firmware via the request_firmware() (hotplug).\n" From a7ddd02b108ecada1cf5a5ccb9362179d5671db4 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:22 -0400 Subject: [PATCH 079/101] qla2xxx: Make debug buffer log easier to view. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 907a7acb1639..589cd13b5a0d 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -13,7 +13,7 @@ * ---------------------------------------------------------------------- * | Module Init and Probe | 0x018f | 0x0146 | * | | | 0x015b-0x0160 | - * | | | 0x016e-0x0170 | + * | | | 0x016e | * | Mailbox commands | 0x1192 | | * | | | | * | Device Discovery | 0x2003 | 0x2016 | @@ -2698,29 +2698,24 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) void ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, - uint8_t *b, uint32_t size) + uint8_t *buf, uint size) { - uint32_t cnt; - uint8_t c; + uint cnt; if (!ql_mask_match(level)) return; - ql_dbg(level, vha, id, " 0 1 2 3 4 5 6 7 8 " - "9 Ah Bh Ch Dh Eh Fh\n"); - ql_dbg(level, vha, id, "----------------------------------" - "----------------------------\n"); - - ql_dbg(level, vha, id, " "); - for (cnt = 0; cnt < size;) { - c = *b++; - printk("%02x", (uint32_t) c); - cnt++; - if (!(cnt % 16)) + ql_dbg(level, vha, id, + "%-+5d 0 1 2 3 4 5 6 7 8 9 A B C D E F\n", size); + ql_dbg(level, vha, id, + "----- -----------------------------------------------\n"); + for (cnt = 0; cnt < size; cnt++, buf++) { + if (cnt % 16 == 0) + ql_dbg(level, vha, id, "%04x:", cnt & ~0xFU); + printk(" %02x", *buf); + if (cnt % 16 == 15) printk("\n"); - else - printk(" "); } - if (cnt % 16) - ql_dbg(level, vha, id, "\n"); + if (cnt % 16 != 0) + printk("\n"); } From fc90adaf05ada86d3fcd145045eac32ad81f41e9 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:23 -0400 Subject: [PATCH 080/101] qla2xxx: Properly initialize IO statistics. Properly initialize IO statistics to avoid initial 0xFFFFFFF (-1) values. Cleanup/simplify usage of pointer to statistics structure. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 50 +++++++++++++++---------------- drivers/scsi/qla2xxx/qla_def.h | 1 - drivers/scsi/qla2xxx/qla_init.c | 3 ++ drivers/scsi/qla2xxx/qla_target.c | 16 +++++----- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index c9bcd82f08bc..e0256a411cd5 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1811,10 +1811,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) int rval; struct link_statistics *stats; dma_addr_t stats_dma; - struct fc_host_statistics *pfc_host_stat; + struct fc_host_statistics *p = &vha->fc_host_stat; - pfc_host_stat = &vha->fc_host_stat; - memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics)); + memset(p, -1, sizeof(*p)); if (IS_QLAFX00(vha->hw)) goto done; @@ -1850,37 +1849,37 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (rval != QLA_SUCCESS) goto done_free; - pfc_host_stat->link_failure_count = stats->link_fail_cnt; - pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt; - pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt; - pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; - pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt; - pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt; + p->link_failure_count = stats->link_fail_cnt; + p->loss_of_sync_count = stats->loss_sync_cnt; + p->loss_of_signal_count = stats->loss_sig_cnt; + p->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; + p->invalid_tx_word_count = stats->inval_xmit_word_cnt; + p->invalid_crc_count = stats->inval_crc_cnt; if (IS_FWI2_CAPABLE(ha)) { - pfc_host_stat->lip_count = stats->lip_cnt; - pfc_host_stat->tx_frames = stats->tx_frames; - pfc_host_stat->rx_frames = stats->rx_frames; - pfc_host_stat->dumped_frames = stats->discarded_frames; - pfc_host_stat->nos_count = stats->nos_rcvd; - pfc_host_stat->error_frames = + p->lip_count = stats->lip_cnt; + p->tx_frames = stats->tx_frames; + p->rx_frames = stats->rx_frames; + p->dumped_frames = stats->discarded_frames; + p->nos_count = stats->nos_rcvd; + p->error_frames = stats->dropped_frames + stats->discarded_frames; - pfc_host_stat->rx_words = vha->qla_stats.input_bytes; - pfc_host_stat->tx_words = vha->qla_stats.output_bytes; + p->rx_words = vha->qla_stats.input_bytes; + p->tx_words = vha->qla_stats.output_bytes; } - pfc_host_stat->fcp_control_requests = vha->qla_stats.control_requests; - pfc_host_stat->fcp_input_requests = vha->qla_stats.input_requests; - pfc_host_stat->fcp_output_requests = vha->qla_stats.output_requests; - pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20; - pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20; - pfc_host_stat->seconds_since_last_reset = + p->fcp_control_requests = vha->qla_stats.control_requests; + p->fcp_input_requests = vha->qla_stats.input_requests; + p->fcp_output_requests = vha->qla_stats.output_requests; + p->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20; + p->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20; + p->seconds_since_last_reset = get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset; - do_div(pfc_host_stat->seconds_since_last_reset, HZ); + do_div(p->seconds_since_last_reset, HZ); done_free: dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics), stats, stats_dma); done: - return pfc_host_stat; + return p; } static void @@ -1888,6 +1887,7 @@ qla2x00_reset_host_stats(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); + memset(&vha->qla_stats, 0, sizeof(vha->qla_stats)); memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat)); vha->qla_stats.jiffies_at_last_reset = get_jiffies_64(); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2b7e4f5574bb..a73ecc780e1a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3508,7 +3508,6 @@ struct qla_hw_data { int cur_vport_count; struct qla_chip_state_84xx *cs84xx; - struct qla_statistics qla_stats; struct isp_operations *isp_ops; struct workqueue_struct *wq; struct qlfc_fw fw_buf; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a3685b683688..68e9309aa5d4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -624,6 +624,9 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + memset(&vha->qla_stats, 0, sizeof(vha->qla_stats)); + memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat)); + /* Clear adapter flags. */ vha->flags.online = 0; ha->flags.chip_reset_done = 0; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index ca39deb4ff5b..bff9689f5ca9 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -215,8 +215,8 @@ static inline void qlt_incr_num_pend_cmds(struct scsi_qla_host *vha) spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); vha->hw->tgt.num_pend_cmds++; - if (vha->hw->tgt.num_pend_cmds > vha->hw->qla_stats.stat_max_pend_cmds) - vha->hw->qla_stats.stat_max_pend_cmds = + if (vha->hw->tgt.num_pend_cmds > vha->qla_stats.stat_max_pend_cmds) + vha->qla_stats.stat_max_pend_cmds = vha->hw->tgt.num_pend_cmds; spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); } @@ -5231,8 +5231,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, if ((vha->hw->tgt.num_qfull_cmds_alloc + 1) > MAX_QFULL_CMDS_ALLOC) { vha->hw->tgt.num_qfull_cmds_dropped++; if (vha->hw->tgt.num_qfull_cmds_dropped > - vha->hw->qla_stats.stat_max_qfull_cmds_dropped) - vha->hw->qla_stats.stat_max_qfull_cmds_dropped = + vha->qla_stats.stat_max_qfull_cmds_dropped) + vha->qla_stats.stat_max_qfull_cmds_dropped = vha->hw->tgt.num_qfull_cmds_dropped; ql_dbg(ql_dbg_io, vha, 0x3068, @@ -5263,8 +5263,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, vha->hw->tgt.num_qfull_cmds_dropped++; if (vha->hw->tgt.num_qfull_cmds_dropped > - vha->hw->qla_stats.stat_max_qfull_cmds_dropped) - vha->hw->qla_stats.stat_max_qfull_cmds_dropped = + vha->qla_stats.stat_max_qfull_cmds_dropped) + vha->qla_stats.stat_max_qfull_cmds_dropped = vha->hw->tgt.num_qfull_cmds_dropped; qlt_chk_exch_leak_thresh_hold(vha); @@ -5293,8 +5293,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, vha->hw->tgt.num_qfull_cmds_alloc++; if (vha->hw->tgt.num_qfull_cmds_alloc > - vha->hw->qla_stats.stat_max_qfull_cmds_alloc) - vha->hw->qla_stats.stat_max_qfull_cmds_alloc = + vha->qla_stats.stat_max_qfull_cmds_alloc) + vha->qla_stats.stat_max_qfull_cmds_alloc = vha->hw->tgt.num_qfull_cmds_alloc; } From c6dc99058e5798958847eab7411083ca5b25643c Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:24 -0400 Subject: [PATCH 081/101] qla2xxx: Properly reset firmware statistics. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 28 ++++++++++++++++++++++++---- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_gbl.h | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 18 ++++++++---------- 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e0256a411cd5..8b06ce8fbb0f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1828,17 +1828,17 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) goto done; stats = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct link_statistics), &stats_dma, GFP_KERNEL); - if (stats == NULL) { + sizeof(*stats), &stats_dma, GFP_KERNEL); + if (!stats) { ql_log(ql_log_warn, vha, 0x707d, "Failed to allocate memory for stats.\n"); goto done; } - memset(stats, 0, DMA_POOL_SIZE); + memset(stats, 0, sizeof(*stats)); rval = QLA_FUNCTION_FAILED; if (IS_FWI2_CAPABLE(ha)) { - rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma); + rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, 0); } else if (atomic_read(&base_vha->loop_state) == LOOP_READY && !ha->dpc_active) { /* Must be in a 'READY' state for statistics retrieval. */ @@ -1886,11 +1886,31 @@ static void qla2x00_reset_host_stats(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); + struct qla_hw_data *ha = vha->hw; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + struct link_statistics *stats; + dma_addr_t stats_dma; memset(&vha->qla_stats, 0, sizeof(vha->qla_stats)); memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat)); vha->qla_stats.jiffies_at_last_reset = get_jiffies_64(); + + if (IS_FWI2_CAPABLE(ha)) { + stats = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*stats), &stats_dma, GFP_KERNEL); + if (!stats) { + ql_log(ql_log_warn, vha, 0x70d7, + "Failed to allocate memory for stats.\n"); + return; + } + + /* reset firmware statistics */ + qla24xx_get_isp_stats(base_vha, stats, stats_dma, BIT_0); + + dma_free_coherent(&ha->pdev->dev, sizeof(*stats), + stats, stats_dma); + } } static void diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 392c147d5793..8cadc4da7d59 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2270,7 +2270,7 @@ qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job) memset(stats, 0, sizeof(struct link_statistics)); - rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma); + rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, 0); if (rval != QLA_SUCCESS) goto done_free; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 589cd13b5a0d..c6ccc8a86fa7 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -41,7 +41,7 @@ * | | | 0x70ad-0x70ae | * | | | 0x70d0-0x70d6 | * | | | 0x70d7-0x70db | - * | | | 0x70de-0x70df | + * | | | 0x70db | * | Task Management | 0x803d | 0x8000,0x800b | * | | | 0x8019 | * | | | 0x8025,0x8026 | diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index fe943772fe7b..be24e6260976 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -344,7 +344,7 @@ qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *, extern int qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, - dma_addr_t); + dma_addr_t, uint); extern int qla24xx_abort_command(srb_t *); extern int qla24xx_async_abort_command(srb_t *); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 9673a0b645ee..583ad62f8d51 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2762,15 +2762,16 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - uint32_t *iter, dwords; + uint32_t *iter = (void *)stats; + ushort dwords = offsetof(typeof(*stats), link_up_cnt)/sizeof(*iter); struct qla_hw_data *ha = vha->hw; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1084, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_LINK_STATUS; - mcp->mb[2] = MSW(stats_dma); - mcp->mb[3] = LSW(stats_dma); + mcp->mb[2] = MSW(LSD(stats_dma)); + mcp->mb[3] = LSW(LSD(stats_dma)); mcp->mb[6] = MSW(MSD(stats_dma)); mcp->mb[7] = LSW(MSD(stats_dma)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; @@ -2799,12 +2800,9 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); rval = QLA_FUNCTION_FAILED; } else { - /* Copy over data -- firmware data is LE. */ + /* Re-endianize - firmware data is le32. */ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1086, "Done %s.\n", __func__); - dwords = offsetof(struct link_statistics, - link_up_cnt) / 4; - iter = &stats->link_fail_cnt; for ( ; dwords--; iter++) le32_to_cpus(iter); } @@ -2818,7 +2816,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, int qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, - dma_addr_t stats_dma) + dma_addr_t stats_dma, uint options) { int rval; mbx_cmd_t mc; @@ -2835,7 +2833,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, mcp->mb[7] = LSW(MSD(stats_dma)); mcp->mb[8] = sizeof(struct link_statistics) / 4; mcp->mb[9] = vha->vp_idx; - mcp->mb[10] = 0; + mcp->mb[10] = options; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; @@ -2850,7 +2848,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, } else { ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108a, "Done %s.\n", __func__); - /* Copy over data -- firmware data is LE. */ + /* Re-endianize - firmware data is le32. */ dwords = sizeof(struct link_statistics) / 4; iter = &stats->link_fail_cnt; for ( ; dwords--; iter++) From 783e0dc4f66ade6bbd8833b6bae778158d54c1a6 Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Wed, 6 Jul 2016 11:14:25 -0400 Subject: [PATCH 082/101] qla2xxx: Check for device state before unloading the driver. During hot swap of PCI device, there can be PCI error on device, during normal driver unload. The race between normal driver unload and driver unload due to PCI error, can lead to system crash.Fix is to check if there is unload going on and allow that function to unload the driver. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_mbx.c | 41 +++++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_os.c | 21 +++++++++++++---- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index c6ccc8a86fa7..2790e5f2f29c 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -14,7 +14,7 @@ * | Module Init and Probe | 0x018f | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | - * | Mailbox commands | 0x1192 | | + * | Mailbox commands | 0x1191 | | * | | | | * | Device Discovery | 0x2003 | 0x2016 | * | | | 0x2011-0x2012, | diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a73ecc780e1a..7d4bd7de3e9c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3658,6 +3658,7 @@ typedef struct scsi_qla_host { #define PFLG_DISCONNECTED 0 /* PCI device removed */ #define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */ #define PFLG_DRIVER_PROBING 2 /* PCI driver .probe */ +#define PCI_ERR 30 uint32_t device_flags; #define SWITCH_FOUND BIT_0 diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 583ad62f8d51..97099ce2df15 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -64,6 +64,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) return QLA_FUNCTION_TIMEOUT; } + /* if PCI error, then avoid mbx processing.*/ + if (test_bit(PCI_ERR, &base_vha->dpc_flags)) { + ql_log(ql_log_warn, vha, 0x1191, + "PCI error, exiting.\n"); + return QLA_FUNCTION_TIMEOUT; + } + reg = ha->iobase; io_lock_on = base_vha->flags.init_done; @@ -266,6 +273,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) uint16_t mb0; uint32_t ictrl; + uint16_t w; if (IS_FWI2_CAPABLE(ha)) { mb0 = RD_REG_WORD(®->isp24.mailbox0); @@ -279,15 +287,32 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "mb[0]=0x%x\n", command, ictrl, jiffies, mb0); ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019); - /* - * Attempt to capture a firmware dump for further analysis - * of the current firmware state. We do not need to do this - * if we are intentionally generating a dump. - */ - if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) - ha->isp_ops->fw_dump(vha, 0); + /* Capture FW dump only, if PCI device active */ + if (!pci_channel_offline(vha->hw->pdev)) { + pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); + if (w == 0xffff || ictrl == 0xffffffff) { + /* This is special case if there is unload + * of driver happening and if PCI device go + * into bad state due to PCI error condition + * then only PCI ERR flag would be set. + * we will do premature exit for above case. + */ + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + set_bit(PCI_ERR, &base_vha->dpc_flags); + ha->flags.mbox_busy = 0; + rval = QLA_FUNCTION_TIMEOUT; + goto premature_exit; + } - rval = QLA_FUNCTION_TIMEOUT; + /* Attempt to capture firmware dump for further + * anallysis of the current formware state. we do not + * need to do this if we are intentionally generating + * a dump + */ + if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) + ha->isp_ops->fw_dump(vha, 0); + rval = QLA_FUNCTION_TIMEOUT; + } } ha->flags.mbox_busy = 0; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f1a2394a99e5..fde7ee17ed85 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -897,12 +897,16 @@ static void qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); while (((qla2x00_reset_active(vha)) || ha->dpc_active || ha->flags.mbox_busy) || test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) || - test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) + test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) { + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + break; msleep(1000); + } } int @@ -2954,10 +2958,7 @@ iospace_config_failed: ha = NULL; probe_out: - pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); - if (test_bit(UNLOADING, &base_vha->dpc_flags)) - return -ENODEV; return ret; } @@ -3138,6 +3139,12 @@ qla2x00_remove_one(struct pci_dev *pdev) qla2x00_wait_for_hba_ready(base_vha); + /* if UNLOAD flag is already set, then continue unload, + * where it was set first. + */ + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + return; + set_bit(UNLOADING, &base_vha->dpc_flags); if (IS_QLAFX00(ha)) @@ -4917,6 +4924,12 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) struct pci_dev *pdev = ha->pdev; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + /* if UNLOAD flag is already set, then continue unload, + * where it was set first. + */ + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + return; + ql_log(ql_log_warn, base_vha, 0x015b, "Disabling adapter.\n"); From ec89146215d124c429bff84b498dccdc4919ffa7 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:26 -0400 Subject: [PATCH 083/101] qla2xxx: Add bsg interface to support D_Port Diagnostics. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 44 ++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_bsg.h | 12 +++++++ drivers/scsi/qla2xxx/qla_dbg.c | 3 +- drivers/scsi/qla2xxx/qla_gbl.h | 3 ++ drivers/scsi/qla2xxx/qla_isr.c | 7 ++-- drivers/scsi/qla2xxx/qla_mbx.c | 58 +++++++++++++++++++++++++++++++++- 6 files changed, 122 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 8cadc4da7d59..592e9249db02 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2295,6 +2295,47 @@ done: return rval; } +static int +qla2x00_do_dport_diagnostics(struct fc_bsg_job *bsg_job) +{ + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + int rval; + struct qla_dport_diag *dd; + + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) + return -EPERM; + + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) { + ql_log(ql_log_warn, vha, 0x70db, + "Failed to allocate memory for dport.\n"); + return -ENOMEM; + } + + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, dd, sizeof(*dd)); + + rval = qla26xx_dport_diagnostics( + vha, dd->buf, sizeof(dd->buf), dd->options); + if (rval == QLA_SUCCESS) { + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd)); + } + + bsg_job->reply->reply_payload_rcv_len = sizeof(*dd); + bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = + rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK; + + bsg_job->reply_len = sizeof(*bsg_job->reply); + bsg_job->reply->result = DID_OK << 16; + bsg_job->job_done(bsg_job); + + kfree(dd); + + return 0; +} + static int qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) { @@ -2362,6 +2403,9 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) case QL_VND_GET_PRIV_STATS: return qla2x00_get_priv_stats(bsg_job); + case QL_VND_DPORT_DIAGNOSTICS: + return qla2x00_do_dport_diagnostics(bsg_job); + default: return -ENOSYS; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index c80192d45536..3b1045f95d6f 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -29,6 +29,7 @@ #define QL_VND_SET_FLASH_UPDATE_CAPS 0x16 #define QL_VND_GET_BBCR_DATA 0x17 #define QL_VND_GET_PRIV_STATS 0x18 +#define QL_VND_DPORT_DIAGNOSTICS 0x19 /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -266,4 +267,15 @@ struct qla_bbcr_data { uint16_t mbx1; /* Port state */ uint8_t reserved[9]; } __packed; + +struct qla_dport_diag { + uint16_t options; + uint32_t buf[16]; + uint8_t unused[62]; +} __packed; + +/* D_Port options */ +#define QLA_DPORT_RESULT 0x0 +#define QLA_DPORT_START 0x2 + #endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 2790e5f2f29c..2a1eb027e162 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -14,7 +14,7 @@ * | Module Init and Probe | 0x018f | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | - * | Mailbox commands | 0x1191 | | + * | Mailbox commands | 0x1196 | | * | | | | * | Device Discovery | 0x2003 | 0x2016 | * | | | 0x2011-0x2012, | @@ -41,7 +41,6 @@ * | | | 0x70ad-0x70ae | * | | | 0x70d0-0x70d6 | * | | | 0x70d7-0x70db | - * | | | 0x70db | * | Task Management | 0x803d | 0x8000,0x800b | * | | | 0x8019 | * | | | 0x8025,0x8026 | diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index be24e6260976..6ca00813c71f 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -445,6 +445,9 @@ qla2x00_port_logout(scsi_qla_host_t *, struct fc_port *); extern int qla2x00_dump_mctp_data(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); +extern int +qla26xx_dport_diagnostics(scsi_qla_host_t *, void *, uint, uint); + /* * Global Function Prototypes in qla_isr.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a2d7935ffeea..6b5f97e8c07b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1152,10 +1152,13 @@ global_port_update: case MBA_DPORT_DIAGNOSTICS: ql_dbg(ql_dbg_async, vha, 0x5052, - "D-Port Diagnostics: %04x %04x=%s\n", mb[0], mb[1], + "D-Port Diagnostics: %04x result=%s index=%u size=%u\n", + mb[0], mb[1] == 0 ? "start" : mb[1] == 1 ? "done (ok)" : - mb[1] == 2 ? "done (error)" : "other"); + mb[1] == 2 ? "done (error)" : "other", + LSB(mb[2]), + mb[3]); break; case MBA_TEMPERATURE_ALERT: diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 97099ce2df15..0f7b83a37a36 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1872,7 +1872,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) states[0] = mcp->mb[1]; if (IS_FWI2_CAPABLE(vha->hw)) { states[1] = mcp->mb[2]; - states[2] = mcp->mb[3]; + states[2] = mcp->mb[3]; /* SFP info */ states[3] = mcp->mb[4]; states[4] = mcp->mb[5]; states[5] = mcp->mb[6]; /* DPORT status */ @@ -5748,3 +5748,59 @@ qla2x00_dump_mctp_data(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr, return rval; } + +int +qla26xx_dport_diagnostics(scsi_qla_host_t *vha, + void *dd_buf, uint size, uint options) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + dma_addr_t dd_dma; + + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192, + "Entered %s.\n", __func__); + + if (size < 1024) { + ql_log(ql_log_warn, vha, 0x1193, "Failed insufficient size.\n"); + return QLA_FUNCTION_PARAMETER_ERROR; + } + + dd_dma = dma_map_single(&vha->hw->pdev->dev, + dd_buf, size, DMA_FROM_DEVICE); + if (!dd_dma) { + ql_log(ql_log_warn, vha, 0x1194, "Failed to map dma buffer.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + memset(dd_buf, 0, size); + + mcp->mb[0] = MBC_DPORT_DIAGNOSTICS; + mcp->mb[1] = options; + mcp->mb[2] = MSW(LSD(dd_dma)); + mcp->mb[3] = LSW(LSD(dd_dma)); + mcp->mb[6] = MSW(MSD(dd_dma)); + mcp->mb[7] = LSW(MSD(dd_dma)); + mcp->mb[8] = size; + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->buf_size = size; + mcp->flags = MBX_DMA_IN; + mcp->tov = MBX_TOV_SECONDS * 4; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x1195, "Failed=%x.\n", rval); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1196, + "Done %s.\n", __func__); + } + + dma_unmap_single(&vha->hw->pdev->dev, dd_dma, + size, DMA_FROM_DEVICE); + + return rval; +} From 8437dda036da5dc839455b5281bd7eac5751765b Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Wed, 6 Jul 2016 11:14:27 -0400 Subject: [PATCH 084/101] qla2xxx: Add bsg interface to support statistics counter reset. [mkp: Folded in compile fix] Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 51 +++++++++++++++++----------------- drivers/scsi/qla2xxx/qla_bsg.h | 1 + 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 592e9249db02..643014f82f7d 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2246,53 +2246,53 @@ qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job) struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); struct link_statistics *stats = NULL; dma_addr_t stats_dma; - int rval = QLA_FUNCTION_FAILED; + int rval; + uint32_t *cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd; + uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0; if (test_bit(UNLOADING, &vha->dpc_flags)) - goto done; + return -ENODEV; if (unlikely(pci_channel_offline(ha->pdev))) - goto done; + return -ENODEV; if (qla2x00_reset_active(vha)) - goto done; + return -EBUSY; if (!IS_FWI2_CAPABLE(ha)) - goto done; + return -EPERM; stats = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct link_statistics), &stats_dma, GFP_KERNEL); + sizeof(*stats), &stats_dma, GFP_KERNEL); if (!stats) { ql_log(ql_log_warn, vha, 0x70e2, - "Failed to allocate memory for stats.\n"); - goto done; + "Failed to allocate memory for stats.\n"); + return -ENOMEM; } - memset(stats, 0, sizeof(struct link_statistics)); + memset(stats, 0, sizeof(*stats)); - rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, 0); + rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options); - if (rval != QLA_SUCCESS) - goto done_free; + if (rval == QLA_SUCCESS) { + ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3, + (uint8_t *)stats, sizeof(*stats)); + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats)); + } - ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3, - (uint8_t *)stats, sizeof(struct link_statistics)); + bsg_job->reply->reply_payload_rcv_len = sizeof(*stats); + bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = + rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK; - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, stats, sizeof(struct link_statistics)); - bsg_job->reply->reply_payload_rcv_len = sizeof(struct link_statistics); - - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; - - bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_job->reply_len = sizeof(*bsg_job->reply); bsg_job->reply->result = DID_OK << 16; bsg_job->job_done(bsg_job); -done_free: - dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics), + dma_free_coherent(&ha->pdev->dev, sizeof(*stats), stats, stats_dma); -done: - return rval; + + return 0; } static int @@ -2401,6 +2401,7 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) return qla27xx_get_bbcr_data(bsg_job); case QL_VND_GET_PRIV_STATS: + case QL_VND_GET_PRIV_STATS_EX: return qla2x00_get_priv_stats(bsg_job); case QL_VND_DPORT_DIAGNOSTICS: diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 3b1045f95d6f..d97dfd521356 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -30,6 +30,7 @@ #define QL_VND_GET_BBCR_DATA 0x17 #define QL_VND_GET_PRIV_STATS 0x18 #define QL_VND_DPORT_DIAGNOSTICS 0x19 +#define QL_VND_GET_PRIV_STATS_EX 0x1A /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 From 40f3862ba91ec1a76ecd848e483db9fc20d279b8 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:28 -0400 Subject: [PATCH 085/101] qla2xxx: Let DPORT be enabled purely by nvram. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 2a1eb027e162..eebd1a585cdd 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -11,7 +11,7 @@ * ---------------------------------------------------------------------- * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- - * | Module Init and Probe | 0x018f | 0x0146 | + * | Module Init and Probe | 0x0191 | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | * | Mailbox commands | 0x1196 | | diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7d4bd7de3e9c..c04d83e6a8b6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3029,6 +3029,7 @@ struct qla_hw_data { uint32_t mr_reset_hdlr_active:1; uint32_t mr_intr_valid:1; + uint32_t dport_enabled:1; uint32_t fawwpn_enabled:1; uint32_t exlogins_enabled:1; uint32_t exchoffld_enabled:1; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 68e9309aa5d4..5b09296b46a3 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2288,13 +2288,13 @@ qla2x00_init_rings(scsi_qla_host_t *vha) mid_init_cb->options = cpu_to_le16(BIT_1); mid_init_cb->init_cb.execution_throttle = cpu_to_le16(ha->cur_fw_xcb_count); - /* D-Port Status */ - if (IS_DPORT_CAPABLE(ha)) - mid_init_cb->init_cb.firmware_options_1 |= - cpu_to_le16(BIT_7); - /* Enable FA-WWPN */ + ha->flags.dport_enabled = + (mid_init_cb->init_cb.firmware_options_1 & BIT_7) != 0; + ql_dbg(ql_dbg_init, vha, 0x0191, "DPORT Support: %s.\n", + (ha->flags.dport_enabled) ? "enabled" : "disabled"); + /* FA-WWPN Status */ ha->flags.fawwpn_enabled = - (mid_init_cb->init_cb.firmware_options_1 & BIT_6) ? 1 : 0; + (mid_init_cb->init_cb.firmware_options_1 & BIT_6) != 0; ql_dbg(ql_dbg_init, vha, 0x0141, "FA-WWPN Support: %s.\n", (ha->flags.fawwpn_enabled) ? "enabled" : "disabled"); } From 41233cd3a454b6f0a6fe9bf4d1c7fc39d9a5179e Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:29 -0400 Subject: [PATCH 086/101] qla2xxx: Add support to handle Loop Init error Asynchronus event. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index eebd1a585cdd..288338d59327 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -30,7 +30,7 @@ * | | | 0x5047 | * | | | 0x5084,0x5075 | * | | | 0x503d,0x5044 | - * | | | 0x507b,0x505f | + * | | | 0x505f | * | Timer Routines | 0x6012 | | * | User Space Interactions | 0x70e3 | 0x7018,0x702e | * | | | 0x7020,0x7024 | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 6b5f97e8c07b..6be2ab4f19a6 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -710,16 +710,23 @@ skip_rio: case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ ql_log(ql_log_warn, vha, 0x5007, - "ISP Response Transfer Error.\n"); + "ISP Response Transfer Error (%x).\n", mb[1]); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ ql_dbg(ql_dbg_async, vha, 0x5008, - "Asynchronous WAKEUP_THRES.\n"); - + "Asynchronous WAKEUP_THRES (%x).\n", mb[1]); break; + + case MBA_LOOP_INIT_ERR: + ql_log(ql_log_warn, vha, 0x507b, + "LOOP INIT ERROR (%x).\n", mb[1]); + ha->isp_ops->fw_dump(vha, 1); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + break; + case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ ql_dbg(ql_dbg_async, vha, 0x5009, "LIP occurred (%x).\n", mb[1]); From ef55e5133c3120ec07434b16d09a7c7f026d8c80 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:30 -0400 Subject: [PATCH 087/101] qla2xxx: Correction to function qla26xx_dport_diagnostics(). Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 8 +++----- drivers/scsi/qla2xxx/qla_mbx.c | 5 ----- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 288338d59327..1a042702d34a 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -14,7 +14,7 @@ * | Module Init and Probe | 0x0191 | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | - * | Mailbox commands | 0x1196 | | + * | Mailbox commands | 0x1196 | 0x1193 | * | | | | * | Device Discovery | 0x2003 | 0x2016 | * | | | 0x2011-0x2012, | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 6be2ab4f19a6..4c800d6ad514 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1159,13 +1159,11 @@ global_port_update: case MBA_DPORT_DIAGNOSTICS: ql_dbg(ql_dbg_async, vha, 0x5052, - "D-Port Diagnostics: %04x result=%s index=%u size=%u\n", + "D-Port Diagnostics: %04x result=%s\n", mb[0], mb[1] == 0 ? "start" : - mb[1] == 1 ? "done (ok)" : - mb[1] == 2 ? "done (error)" : "other", - LSB(mb[2]), - mb[3]); + mb[1] == 1 ? "done (pass)" : + mb[1] == 2 ? "done (error)" : "other"); break; case MBA_TEMPERATURE_ALERT: diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 0f7b83a37a36..bf16e6f5dbf5 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -5764,11 +5764,6 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192, "Entered %s.\n", __func__); - if (size < 1024) { - ql_log(ql_log_warn, vha, 0x1193, "Failed insufficient size.\n"); - return QLA_FUNCTION_PARAMETER_ERROR; - } - dd_dma = dma_map_single(&vha->hw->pdev->dev, dd_buf, size, DMA_FROM_DEVICE); if (!dd_dma) { From 9e052e2d4f5fe5a6f5f6d5153dd3075160fa8fcb Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 6 Jul 2016 11:14:31 -0400 Subject: [PATCH 088/101] qla2xxx: Separate ISP type bits out from device type. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 6 +++-- drivers/scsi/qla2xxx/qla_os.c | 44 +++++++++++++++++----------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c04d83e6a8b6..ae4a74756128 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3130,7 +3130,7 @@ struct qla_hw_data { #define PCI_DEVICE_ID_QLOGIC_ISP2271 0x2271 #define PCI_DEVICE_ID_QLOGIC_ISP2261 0x2261 - uint32_t device_type; + uint32_t isp_type; #define DT_ISP2100 BIT_0 #define DT_ISP2200 BIT_1 #define DT_ISP2300 BIT_2 @@ -3155,6 +3155,7 @@ struct qla_hw_data { #define DT_ISP2261 BIT_21 #define DT_ISP_LAST (DT_ISP2261 << 1) + uint32_t device_type; #define DT_T10_PI BIT_25 #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 @@ -3162,7 +3163,8 @@ struct qla_hw_data { #define DT_OEM_001 BIT_29 #define DT_ISP2200A BIT_30 #define DT_EXTENDED_IDS BIT_31 -#define DT_MASK(ha) ((ha)->device_type & (DT_ISP_LAST - 1)) + +#define DT_MASK(ha) ((ha)->isp_type & (DT_ISP_LAST - 1)) #define IS_QLA2100(ha) (DT_MASK(ha) & DT_ISP2100) #define IS_QLA2200(ha) (DT_MASK(ha) & DT_ISP2200) #define IS_QLA2300(ha) (DT_MASK(ha) & DT_ISP2300) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fde7ee17ed85..dc7e58315870 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2110,27 +2110,27 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->device_type = DT_EXTENDED_IDS; switch (ha->pdev->device) { case PCI_DEVICE_ID_QLOGIC_ISP2100: - ha->device_type |= DT_ISP2100; + ha->isp_type |= DT_ISP2100; ha->device_type &= ~DT_EXTENDED_IDS; ha->fw_srisc_address = RISC_START_ADDRESS_2100; break; case PCI_DEVICE_ID_QLOGIC_ISP2200: - ha->device_type |= DT_ISP2200; + ha->isp_type |= DT_ISP2200; ha->device_type &= ~DT_EXTENDED_IDS; ha->fw_srisc_address = RISC_START_ADDRESS_2100; break; case PCI_DEVICE_ID_QLOGIC_ISP2300: - ha->device_type |= DT_ISP2300; + ha->isp_type |= DT_ISP2300; ha->device_type |= DT_ZIO_SUPPORTED; ha->fw_srisc_address = RISC_START_ADDRESS_2300; break; case PCI_DEVICE_ID_QLOGIC_ISP2312: - ha->device_type |= DT_ISP2312; + ha->isp_type |= DT_ISP2312; ha->device_type |= DT_ZIO_SUPPORTED; ha->fw_srisc_address = RISC_START_ADDRESS_2300; break; case PCI_DEVICE_ID_QLOGIC_ISP2322: - ha->device_type |= DT_ISP2322; + ha->isp_type |= DT_ISP2322; ha->device_type |= DT_ZIO_SUPPORTED; if (ha->pdev->subsystem_vendor == 0x1028 && ha->pdev->subsystem_device == 0x0170) @@ -2138,60 +2138,60 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2300; break; case PCI_DEVICE_ID_QLOGIC_ISP6312: - ha->device_type |= DT_ISP6312; + ha->isp_type |= DT_ISP6312; ha->fw_srisc_address = RISC_START_ADDRESS_2300; break; case PCI_DEVICE_ID_QLOGIC_ISP6322: - ha->device_type |= DT_ISP6322; + ha->isp_type |= DT_ISP6322; ha->fw_srisc_address = RISC_START_ADDRESS_2300; break; case PCI_DEVICE_ID_QLOGIC_ISP2422: - ha->device_type |= DT_ISP2422; + ha->isp_type |= DT_ISP2422; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP2432: - ha->device_type |= DT_ISP2432; + ha->isp_type |= DT_ISP2432; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP8432: - ha->device_type |= DT_ISP8432; + ha->isp_type |= DT_ISP8432; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP5422: - ha->device_type |= DT_ISP5422; + ha->isp_type |= DT_ISP5422; ha->device_type |= DT_FWI2; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP5432: - ha->device_type |= DT_ISP5432; + ha->isp_type |= DT_ISP5432; ha->device_type |= DT_FWI2; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP2532: - ha->device_type |= DT_ISP2532; + ha->isp_type |= DT_ISP2532; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP8001: - ha->device_type |= DT_ISP8001; + ha->isp_type |= DT_ISP8001; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP8021: - ha->device_type |= DT_ISP8021; + ha->isp_type |= DT_ISP8021; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->fw_srisc_address = RISC_START_ADDRESS_2400; @@ -2199,7 +2199,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) qla82xx_init_flags(ha); break; case PCI_DEVICE_ID_QLOGIC_ISP8044: - ha->device_type |= DT_ISP8044; + ha->isp_type |= DT_ISP8044; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->fw_srisc_address = RISC_START_ADDRESS_2400; @@ -2207,7 +2207,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) qla82xx_init_flags(ha); break; case PCI_DEVICE_ID_QLOGIC_ISP2031: - ha->device_type |= DT_ISP2031; + ha->isp_type |= DT_ISP2031; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; @@ -2215,7 +2215,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP8031: - ha->device_type |= DT_ISP8031; + ha->isp_type |= DT_ISP8031; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; @@ -2223,10 +2223,10 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISPF001: - ha->device_type |= DT_ISPFX00; + ha->isp_type |= DT_ISPFX00; break; case PCI_DEVICE_ID_QLOGIC_ISP2071: - ha->device_type |= DT_ISP2071; + ha->isp_type |= DT_ISP2071; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; @@ -2234,7 +2234,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP2271: - ha->device_type |= DT_ISP2271; + ha->isp_type |= DT_ISP2271; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; @@ -2242,7 +2242,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; case PCI_DEVICE_ID_QLOGIC_ISP2261: - ha->device_type |= DT_ISP2261; + ha->isp_type |= DT_ISP2261; ha->device_type |= DT_ZIO_SUPPORTED; ha->device_type |= DT_FWI2; ha->device_type |= DT_IIDMA; From a465537ad1a4423e542f9427e4f684334b4b40a5 Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Wed, 6 Jul 2016 11:14:32 -0400 Subject: [PATCH 089/101] qla2xxx: Disable the adapter and skip error recovery in case of register disconnect. If there is error recovery going on due to command timeout and there is register disconnect, then disable the adapter. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 3 ++ drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 8b06ce8fbb0f..fe7469c901f7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1769,6 +1769,9 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) if (!fcport) return; + if (test_bit(UNLOADING, &fcport->vha->dpc_flags)) + return; + if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) return; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 1a042702d34a..97b0a9da0913 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -41,7 +41,7 @@ * | | | 0x70ad-0x70ae | * | | | 0x70d0-0x70d6 | * | | | 0x70d7-0x70db | - * | Task Management | 0x803d | 0x8000,0x800b | + * | Task Management | 0x8042 | 0x8000,0x800b | * | | | 0x8019 | * | | | 0x8025,0x8026 | * | | | 0x8031,0x8032 | diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index dc7e58315870..2674f4c16bc3 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -943,6 +943,30 @@ sp_get(struct srb *sp) atomic_inc(&sp->ref_count); } +#define ISP_REG_DISCONNECT 0xffffffffU +/************************************************************************** +* qla2x00_isp_reg_stat +* +* Description: +* Read the host status register of ISP before aborting the command. +* +* Input: +* ha = pointer to host adapter structure. +* +* +* Returns: +* Either true or false. +* +* Note: Return true if there is register disconnect. +**************************************************************************/ +static inline +uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha) +{ + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + return ((RD_REG_DWORD(®->host_status)) == ISP_REG_DISCONNECT); +} + /************************************************************************** * qla2xxx_eh_abort * @@ -970,6 +994,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) int rval, wait = 0; struct qla_hw_data *ha = vha->hw; + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, vha, 0x8042, + "PCI/Register disconnect, exiting.\n"); + return FAILED; + } if (!CMD_SP(cmd)) return SUCCESS; @@ -1153,6 +1182,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) scsi_qla_host_t *vha = shost_priv(cmd->device->host); struct qla_hw_data *ha = vha->hw; + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, vha, 0x803e, + "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, ha->isp_ops->lun_reset); } @@ -1163,6 +1198,12 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) scsi_qla_host_t *vha = shost_priv(cmd->device->host); struct qla_hw_data *ha = vha->hw; + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, vha, 0x803f, + "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, ha->isp_ops->target_reset); } @@ -1190,6 +1231,13 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) int ret = FAILED; unsigned int id; uint64_t lun; + struct qla_hw_data *ha = vha->hw; + + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, vha, 0x8040, + "PCI/Register disconnect, exiting.\n"); + return FAILED; + } id = cmd->device->id; lun = cmd->device->lun; @@ -1259,6 +1307,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) uint64_t lun; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, vha, 0x8041, + "PCI/Register disconnect, exiting.\n"); + schedule_work(&ha->board_disable); + return SUCCESS; + } + id = cmd->device->id; lun = cmd->device->lun; From 75d560e09524660a2c67a49f01ca688bd6b623c2 Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Wed, 6 Jul 2016 11:14:33 -0400 Subject: [PATCH 090/101] qla2xxx: Fix duplicate message id. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dbg.c | 7 +++---- drivers/scsi/qla2xxx/qla_isr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 97b0a9da0913..45af34ddc432 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -14,9 +14,8 @@ * | Module Init and Probe | 0x0191 | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | - * | Mailbox commands | 0x1196 | 0x1193 | - * | | | | - * | Device Discovery | 0x2003 | 0x2016 | + * | Mailbox commands | 0x1199 | 0x1193 | + * | Device Discovery | 0x2004 | 0x2016 | * | | | 0x2011-0x2012, | * | | | 0x2099-0x20a4 | * | Queue Command and IO tracing | 0x3074 | 0x300b | @@ -26,7 +25,7 @@ * | | | 0x3036,0x3038 | * | | | 0x303a | * | DPC Thread | 0x4023 | 0x4002,0x4013 | - * | Async Events | 0x5089 | 0x502b-0x502f | + * | Async Events | 0x5090 | 0x502b-0x502f | * | | | 0x5047 | * | | | 0x5084,0x5075 | * | | | 0x503d,0x5044 | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 4c800d6ad514..987f1c729e9c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -721,7 +721,7 @@ skip_rio: break; case MBA_LOOP_INIT_ERR: - ql_log(ql_log_warn, vha, 0x507b, + ql_log(ql_log_warn, vha, 0x5090, "LOOP INIT ERROR (%x).\n", mb[1]); ha->isp_ops->fw_dump(vha, 1); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bf16e6f5dbf5..23698c998699 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -404,7 +404,7 @@ mbx_done: "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n", mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command); - ql_dbg(ql_dbg_disc, vha, 0x1115, + ql_dbg(ql_dbg_mbx, vha, 0x1198, "host status: 0x%x, flags:0x%lx, intr ctrl reg:0x%x, intr status:0x%x\n", RD_REG_DWORD(®->isp24.host_status), ha->fw_dump_cap_flags, @@ -413,7 +413,7 @@ mbx_done: mbx_reg = ®->isp24.mailbox0; for (i = 0; i < 6; i++) - ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x1116, + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1199, "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++)); } else { ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__); From 061b5c3c48a1e276f8fd539bfa8aab8b359ffc31 Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Wed, 6 Jul 2016 11:14:34 -0400 Subject: [PATCH 091/101] qla2xxx: Fix BBCR offset Fixes: 969a619 ("qla2xxx: Add support for buffer to buffer credit value for ISP27XX.") Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_fw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 4c0f3a774799..8a2368b32dec 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1288,7 +1288,7 @@ struct vp_rpt_id_entry_24xx { uint8_t vp_idx_map[16]; - uint8_t reserved_4[28]; + uint8_t reserved_4[24]; uint16_t bbcr; uint8_t reserved_5[6]; }; From 094f71c70b5c25176709081cedda23228a0d82ab Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Wed, 6 Jul 2016 11:14:35 -0400 Subject: [PATCH 092/101] qla2xxx: Update driver version to 8.07.00.38-k Signed-off-by: Himanshu Madhani Signed-off-by: Giridhar Malavali Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 0bc93fa46dae..3cb1964b7786 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.07.00.33-k" +#define QLA2XXX_VERSION "8.07.00.38-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 7 From 64ce60cab24603ac0fcd59c9fbc3be78f4c4d229 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Fri, 1 Jul 2016 13:37:31 -0500 Subject: [PATCH 093/101] hpsa: correct skipping masked peripherals The SA controller spins down RAID drive spares. A REGNEWD event causes an inquiry to be sent to all physical drives. This causes the SA controller to spin up the spare. The controller suspends all I/O to a logical volume until the spare is spun up. The spin-up can take over 50 seconds. This can result in one or both of the following: - SML sends down aborts and resets to the logical volume and can cause the logical volume to be off-lined. - a negative impact on the logical volume's I/O performance each time a REGNEWD is triggered. Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 79 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ff8dcd5b0631..375a39632a7a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4105,6 +4105,70 @@ static int hpsa_set_local_logical_count(struct ctlr_info *h, return rc; } +static bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes) +{ + struct bmic_identify_physical_device *id_phys; + bool is_spare = false; + int rc; + + id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); + if (!id_phys) + return false; + + rc = hpsa_bmic_id_physical_device(h, + lunaddrbytes, + GET_BMIC_DRIVE_NUMBER(lunaddrbytes), + id_phys, sizeof(*id_phys)); + if (rc == 0) + is_spare = (id_phys->more_flags >> 6) & 0x01; + + kfree(id_phys); + return is_spare; +} + +#define RPL_DEV_FLAG_NON_DISK 0x1 +#define RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED 0x2 +#define RPL_DEV_FLAG_UNCONFIG_DISK 0x4 + +#define BMIC_DEVICE_TYPE_ENCLOSURE 6 + +static bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes, + struct ext_report_lun_entry *rle) +{ + u8 device_flags; + u8 device_type; + + if (!MASKED_DEVICE(lunaddrbytes)) + return false; + + device_flags = rle->device_flags; + device_type = rle->device_type; + + if (device_flags & RPL_DEV_FLAG_NON_DISK) { + if (device_type == BMIC_DEVICE_TYPE_ENCLOSURE) + return false; + return true; + } + + if (!(device_flags & RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED)) + return false; + + if (device_flags & RPL_DEV_FLAG_UNCONFIG_DISK) + return false; + + /* + * Spares may be spun down, we do not want to + * do an Inquiry to a RAID set spare drive as + * that would have them spun up, that is a + * performance hit because I/O to the RAID device + * stops while the spin up occurs which can take + * over 50 seconds. + */ + if (hpsa_is_disk_spare(h, lunaddrbytes)) + return true; + + return false; +} static void hpsa_update_scsi_devices(struct ctlr_info *h) { @@ -4198,6 +4262,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) u8 *lunaddrbytes, is_OBDR = 0; int rc = 0; int phys_dev_index = i - (raid_ctlr_position == 0); + bool skip_device = false; physical_device = i < nphysicals + (raid_ctlr_position == 0); @@ -4205,11 +4270,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, i, nphysicals, nlogicals, physdev_list, logdev_list); - /* skip masked non-disk devices */ - if (MASKED_DEVICE(lunaddrbytes) && physical_device && - (physdev_list->LUN[phys_dev_index].device_type != 0x06) && - (physdev_list->LUN[phys_dev_index].device_flags & 0x01)) - continue; + /* + * Skip over some devices such as a spare. + */ + if (!tmpdevice->external && physical_device) { + skip_device = hpsa_skip_device(h, lunaddrbytes, + &physdev_list->LUN[phys_dev_index]); + if (skip_device) + continue; + } /* Get device type, vendor, model, device id */ rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice, From 3fb134cb4c170debf2b786d689fe263186feea4b Mon Sep 17 00:00:00 2001 From: Don Brace Date: Fri, 1 Jul 2016 13:37:38 -0500 Subject: [PATCH 094/101] hpsa: change hpsa_passthru_ioctl timeout Was not alloting for FW Flash times. Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 375a39632a7a..030d0023e1d2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6524,7 +6524,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, - DEFAULT_TIMEOUT); + NO_TIMEOUT); if (iocommand.buf_size > 0) hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -6657,7 +6657,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[--i].Ext = cpu_to_le32(HPSA_SG_LAST); } status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, - DEFAULT_TIMEOUT); + NO_TIMEOUT); if (sg_used) hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); From fcbefc3b2bfb4dd1a230b3082b68bc7cf7c081e7 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Sat, 25 Jun 2016 12:35:22 +0800 Subject: [PATCH 095/101] scsi: ufs: remove unnecessary goto label When buff_ascii kmalloc failed, there is no need to call kfree, it should return -ENOMEM directly, this patch fixes it. Signed-off-by: Tiezhu Yang Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8e8989a1859b..f08d41a2d70b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2137,7 +2137,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, buff_ascii = kmalloc(ascii_len, GFP_KERNEL); if (!buff_ascii) { err = -ENOMEM; - goto out_free_buff; + goto out; } /* @@ -2156,7 +2156,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, size - QUERY_DESC_HDR_SIZE); memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len); buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE; -out_free_buff: kfree(buff_ascii); } out: From 31979008fdae72d7441643f3a5b1bdaedf481335 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 18 Jul 2016 16:06:03 +0200 Subject: [PATCH 096/101] lpfc: call lpfc_sli_validate_fcp_iocb() with the hbalock held Call lpfc_sli_validate_fcp_iocb() with the hbalock held, as the pointer to iocbq is not guaranteed to still be valid after looking it up. Signed-off-by: Johannes Thumshirn Reviewed-by: Laurence Oberman Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c8fd0a349eba..351d08ace24a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10203,6 +10203,7 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, struct lpfc_iocbq *iocbq; int sum, i; + spin_lock_irq(&phba->hbalock); for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; @@ -10210,6 +10211,7 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, ctx_cmd) == 0) sum++; } + spin_unlock_irq(&phba->hbalock); return sum; } From b3d30f4a24f0ef9ba04bd9dc84523c6c9d18c11b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 19 Jul 2016 13:49:39 +0200 Subject: [PATCH 097/101] fcoe: Rename 'fip_frame' to 'fip_vn2vn_notify_frame' Do not use a generic name to avoid confusions with other usages. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_ctlr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 26a0685c74d1..dd455312de41 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1989,7 +1989,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, const u8 *dest, size_t min_len) { struct sk_buff *skb; - struct fip_frame { + struct fip_vn2vn_probe_frame { struct ethhdr eth; struct fip_header fip; struct fip_mac_desc mac; @@ -2016,7 +2016,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, if (!skb) return; - frame = (struct fip_frame *)skb->data; + frame = (struct fip_vn2vn_probe_frame *)skb->data; memset(frame, 0, len); memcpy(frame->eth.h_dest, dest, ETH_ALEN); From 9a6cf881df0293cc1c06d31bcbeda6c23b95dcac Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 19 Jul 2016 13:49:40 +0200 Subject: [PATCH 098/101] fcoe: implement FIP VLAN responder When running in VN2VN mode there is no central instance which would send out any FIP VLAN discovery notifications. So this patch adds a new sysfs attribute 'fip_vlan_responder' which will activate a FIP VLAN discovery responder. Signed-off-by: Hannes Reinecke Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 6 + drivers/scsi/fcoe/fcoe_ctlr.c | 224 +++++++++++++++++++++++++++++++++ drivers/scsi/fcoe/fcoe_sysfs.c | 39 ++++++ include/scsi/libfc.h | 1 + include/scsi/libfcoe.h | 5 +- 5 files changed, 274 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 61eda7498c90..c8a4305c7662 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -673,6 +673,12 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) fcoe = port->priv; ctlr = fcoe_to_ctlr(fcoe); + /* Figure out the VLAN ID, if any */ + if (netdev->priv_flags & IFF_802_1Q_VLAN) + lport->vlan = vlan_dev_vlan_id(netdev); + else + lport->vlan = 0; + /* * Determine max frame size based on underlying device and optional * user-configured limit. If the MFS is too low, fcoe_link_ok() diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index dd455312de41..a569c65f22b1 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -59,6 +59,8 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *); static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *); static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *); +static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *, struct sk_buff *); + static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS; @@ -149,6 +151,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) { fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT); fip->mode = mode; + fip->fip_resp = false; INIT_LIST_HEAD(&fip->fcfs); mutex_init(&fip->ctlr_mutex); spin_lock_init(&fip->ctlr_lock); @@ -1513,6 +1516,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) struct fip_header *fiph; struct ethhdr *eh; enum fip_state state; + bool fip_vlan_resp = false; u16 op; u8 sub; @@ -1546,11 +1550,17 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) state = FIP_ST_ENABLED; LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); } + fip_vlan_resp = fip->fip_resp; mutex_unlock(&fip->ctlr_mutex); if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN) return fcoe_ctlr_vn_recv(fip, skb); + if (fip_vlan_resp && op == FIP_OP_VLAN) { + LIBFCOE_FIP_DBG(fip, "fip vlan discovery\n"); + return fcoe_ctlr_vlan_recv(fip, skb); + } + if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP && state != FIP_ST_VNMP_CLAIM) goto drop; @@ -2703,6 +2713,220 @@ drop: return rc; } +/** + * fcoe_ctlr_vlan_parse - parse vlan discovery request or response + * @fip: The FCoE controller + * @skb: incoming packet + * @rdata: buffer for resulting parsed VLAN entry plus fcoe_rport + * + * Returns non-zero error number on error. + * Does not consume the packet. + */ +static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip, + struct sk_buff *skb, + struct fc_rport_priv *rdata) +{ + struct fip_header *fiph; + struct fip_desc *desc = NULL; + struct fip_mac_desc *macd = NULL; + struct fip_wwn_desc *wwn = NULL; + struct fcoe_rport *frport; + size_t rlen; + size_t dlen; + u32 desc_mask = 0; + u32 dtype; + u8 sub; + + memset(rdata, 0, sizeof(*rdata) + sizeof(*frport)); + frport = fcoe_ctlr_rport(rdata); + + fiph = (struct fip_header *)skb->data; + frport->flags = ntohs(fiph->fip_flags); + + sub = fiph->fip_subcode; + switch (sub) { + case FIP_SC_VL_REQ: + desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME); + break; + default: + LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub); + return -EINVAL; + } + + rlen = ntohs(fiph->fip_dl_len) * 4; + if (rlen + sizeof(*fiph) > skb->len) + return -EINVAL; + + desc = (struct fip_desc *)(fiph + 1); + while (rlen > 0) { + dlen = desc->fip_dlen * FIP_BPW; + if (dlen < sizeof(*desc) || dlen > rlen) + return -EINVAL; + + dtype = desc->fip_dtype; + if (dtype < 32) { + if (!(desc_mask & BIT(dtype))) { + LIBFCOE_FIP_DBG(fip, + "unexpected or duplicated desc " + "desc type %u in " + "FIP VN2VN subtype %u\n", + dtype, sub); + return -EINVAL; + } + desc_mask &= ~BIT(dtype); + } + + switch (dtype) { + case FIP_DT_MAC: + if (dlen != sizeof(struct fip_mac_desc)) + goto len_err; + macd = (struct fip_mac_desc *)desc; + if (!is_valid_ether_addr(macd->fd_mac)) { + LIBFCOE_FIP_DBG(fip, + "Invalid MAC addr %pM in FIP VN2VN\n", + macd->fd_mac); + return -EINVAL; + } + memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN); + break; + case FIP_DT_NAME: + if (dlen != sizeof(struct fip_wwn_desc)) + goto len_err; + wwn = (struct fip_wwn_desc *)desc; + rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn); + break; + default: + LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " + "in FIP probe\n", dtype); + /* standard says ignore unknown descriptors >= 128 */ + if (dtype < FIP_DT_NON_CRITICAL) + return -EINVAL; + break; + } + desc = (struct fip_desc *)((char *)desc + dlen); + rlen -= dlen; + } + return 0; + +len_err: + LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", + dtype, dlen); + return -EINVAL; +} + +/** + * fcoe_ctlr_vlan_send() - Send a FIP VLAN Notification + * @fip: The FCoE controller + * @sub: sub-opcode for vlan notification or vn2vn vlan notification + * @dest: The destination Ethernet MAC address + * @min_len: minimum size of the Ethernet payload to be sent + */ +static void fcoe_ctlr_vlan_send(struct fcoe_ctlr *fip, + enum fip_vlan_subcode sub, + const u8 *dest) +{ + struct sk_buff *skb; + struct fip_vlan_notify_frame { + struct ethhdr eth; + struct fip_header fip; + struct fip_mac_desc mac; + struct fip_vlan_desc vlan; + } __packed * frame; + size_t len; + size_t dlen; + + len = sizeof(*frame); + dlen = sizeof(frame->mac) + sizeof(frame->vlan); + len = max(len, sizeof(struct ethhdr)); + + skb = dev_alloc_skb(len); + if (!skb) + return; + + LIBFCOE_FIP_DBG(fip, "fip %s vlan notification, vlan %d\n", + fip->mode == FIP_MODE_VN2VN ? "vn2vn" : "fcf", + fip->lp->vlan); + + frame = (struct fip_vlan_notify_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); + frame->eth.h_proto = htons(ETH_P_FIP); + + frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); + frame->fip.fip_op = htons(FIP_OP_VLAN); + frame->fip.fip_subcode = sub; + frame->fip.fip_dl_len = htons(dlen / FIP_BPW); + + frame->mac.fd_desc.fip_dtype = FIP_DT_MAC; + frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW; + memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); + + frame->vlan.fd_desc.fip_dtype = FIP_DT_VLAN; + frame->vlan.fd_desc.fip_dlen = sizeof(frame->vlan) / FIP_BPW; + put_unaligned_be16(fip->lp->vlan, &frame->vlan.fd_vlan); + + skb_put(skb, len); + skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + + fip->send(fip, skb); +} + +/** + * fcoe_ctlr_vlan_disk_reply() - send FIP VLAN Discovery Notification. + * @fip: The FCoE controller + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vlan_disc_reply(struct fcoe_ctlr *fip, + struct fc_rport_priv *rdata) +{ + struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); + enum fip_vlan_subcode sub = FIP_SC_VL_NOTE; + + if (fip->mode == FIP_MODE_VN2VN) + sub = FIP_SC_VL_VN2VN_NOTE; + + fcoe_ctlr_vlan_send(fip, sub, frport->enode_mac); +} + +/** + * fcoe_ctlr_vlan_recv - vlan request receive handler for VN2VN mode. + * @lport: The local port + * @fp: The received frame + * + */ +static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) +{ + struct fip_header *fiph; + enum fip_vlan_subcode sub; + struct { + struct fc_rport_priv rdata; + struct fcoe_rport frport; + } buf; + int rc; + + fiph = (struct fip_header *)skb->data; + sub = fiph->fip_subcode; + rc = fcoe_ctlr_vlan_parse(fip, skb, &buf.rdata); + if (rc) { + LIBFCOE_FIP_DBG(fip, "vlan_recv vlan_parse error %d\n", rc); + goto drop; + } + mutex_lock(&fip->ctlr_mutex); + if (sub == FIP_SC_VL_REQ) + fcoe_ctlr_vlan_disc_reply(fip, &buf.rdata); + mutex_unlock(&fip->ctlr_mutex); + +drop: + kfree(skb); + return rc; +} + /** * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode. * @lport: The local port diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 045c4e11ee54..0675fd128734 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -385,6 +385,44 @@ static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR, show_ctlr_enabled_state, store_ctlr_enabled); +static ssize_t store_ctlr_fip_resp(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); + struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr); + + mutex_lock(&fip->ctlr_mutex); + if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) { + if (buf[0] == '1') { + fip->fip_resp = 1; + mutex_unlock(&fip->ctlr_mutex); + return count; + } + if (buf[0] == '0') { + fip->fip_resp = 0; + mutex_unlock(&fip->ctlr_mutex); + return count; + } + } + mutex_unlock(&fip->ctlr_mutex); + return -EINVAL; +} + +static ssize_t show_ctlr_fip_resp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); + struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr); + + return sprintf(buf, "%d\n", fip->fip_resp ? 1 : 0); +} + +static FCOE_DEVICE_ATTR(ctlr, fip_vlan_responder, S_IRUGO | S_IWUSR, + show_ctlr_fip_resp, + store_ctlr_fip_resp); + static ssize_t store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, struct device_attribute *attr, @@ -467,6 +505,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = { }; static struct attribute *fcoe_ctlr_attrs[] = { + &device_attr_fcoe_ctlr_fip_vlan_responder.attr, &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, &device_attr_fcoe_ctlr_enabled.attr, &device_attr_fcoe_ctlr_mode.attr, diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 93d14daf0994..7428a53257ca 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -878,6 +878,7 @@ struct fc_lport { struct libfc_function_template tt; u8 link_up; u8 qfull; + u16 vlan; enum fc_lport_state state; unsigned long boot_time; struct fc_host_statistics host_stats; diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index bcc5c3e82977..722d3264d3bf 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -110,8 +110,10 @@ enum fip_mode { * @flogi_req_send: send of FLOGI requested * @flogi_count: number of FLOGI attempts in AUTO mode. * @map_dest: use the FC_MAP mode for destination MAC addresses. + * @fip_resp: start FIP VLAN discovery responder * @spma: supports SPMA server-provided MACs mode * @probe_tries: number of FC_IDs probed + * @priority: DCBx FCoE APP priority * @dest_addr: MAC address of the selected FC forwarder. * @ctl_src_addr: the native MAC address of our local port. * @send: LLD-supplied function to handle sending FIP Ethernet frames @@ -149,7 +151,8 @@ struct fcoe_ctlr { u16 flogi_oxid; u8 flogi_req_send; u8 flogi_count; - u8 map_dest; + bool map_dest; + bool fip_resp; u8 spma; u8 probe_tries; u8 priority; From de8c36bba33380fcc8564e69c039a4b84166e66d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 22:42:17 +0200 Subject: [PATCH 099/101] scsi: lpfc: avoid harmless comparison warning When building with -Wextra, we get a lot of warnings for the lpfc driver concerning expressions that are always true, starting with: drivers/scsi/lpfc/lpfc_attr.c: In function 'lpfc_enable_npiv_init': drivers/scsi/lpfc/lpfc_attr.c:2786:77: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits] drivers/scsi/lpfc/lpfc_attr.c: In function 'lpfc_enable_rrq_init': drivers/scsi/lpfc/lpfc_attr.c:2802:76: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits] drivers/scsi/lpfc/lpfc_attr.c: In function 'lpfc_suppress_link_up_init': drivers/scsi/lpfc/lpfc_attr.c:2812:2050: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits] drivers/scsi/lpfc/lpfc_attr.c: In function 'lpfc_log_verbose_init': drivers/scsi/lpfc/lpfc_attr.c:3064:1930: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits] The code works as intended, but it would be nice to shut up the warning so we don't clutter up build logs with this. Using a separate inline function for it makes it clear to the compiler that the comparison is necessary in the caller but still lets it do the constant-folding. [mkp: fix typo] Signed-off-by: Arnd Bergmann Reviewed-by: Johannes Thumshirn Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6793df86a425..f1019908800e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1621,6 +1621,11 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); } +static inline bool lpfc_rangecheck(uint val, uint min, uint max) +{ + return val >= min && val <= max; +} + /** * lpfc_param_show - Return a cfg attribute value in decimal * @@ -1698,7 +1703,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ static int \ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ { \ - if (val >= minval && val <= maxval) {\ + if (lpfc_rangecheck(val, minval, maxval)) {\ phba->cfg_##attr = val;\ return 0;\ }\ @@ -1733,7 +1738,7 @@ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ static int \ lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \ { \ - if (val >= minval && val <= maxval) {\ + if (lpfc_rangecheck(val, minval, maxval)) {\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ "3052 lpfc_" #attr " changed from %d to %d\n", \ phba->cfg_##attr, val); \ @@ -1857,7 +1862,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ static int \ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ { \ - if (val >= minval && val <= maxval) {\ + if (lpfc_rangecheck(val, minval, maxval)) {\ vport->cfg_##attr = val;\ return 0;\ }\ @@ -1889,7 +1894,7 @@ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ static int \ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ { \ - if (val >= minval && val <= maxval) {\ + if (lpfc_rangecheck(val, minval, maxval)) {\ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ "3053 lpfc_" #attr \ " changed from %d (x%x) to %d (x%x)\n", \ From dd7328e4c53649c1c7ec36bc1cf5b229b8662047 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Jul 2016 11:23:59 +0300 Subject: [PATCH 100/101] fnic: pci_dma_mapping_error() doesn't return an error code pci_dma_mapping_error() returns true on error and false on success. Fixes: fd6ddfa4c1dd ('fnic: check pci_map_single() return value') Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_fcs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 0d532ae273eb..3b7da66e2771 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -954,8 +954,8 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) skb_put(skb, len); pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); - r = pci_dma_mapping_error(fnic->pdev, pa); - if (r) { + if (pci_dma_mapping_error(fnic->pdev, pa)) { + r = -ENOMEM; printk(KERN_ERR "PCI mapping failed with error %d\n", r); goto free_skb; } @@ -1093,8 +1093,8 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); - ret = pci_dma_mapping_error(fnic->pdev, pa); - if (ret) { + if (pci_dma_mapping_error(fnic->pdev, pa)) { + ret = -ENOMEM; printk(KERN_ERR "DMA map failed with error %d\n", ret); goto free_skb_on_err; } From 354a086d9369cb7471790fa047665884f2bc6d79 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Wed, 6 Jul 2016 17:00:25 +0800 Subject: [PATCH 101/101] scsi:libsas: fix oops caused by assigning a freed task to ->lldd_task A freed task has been assigned to ->lldd_task when lldd_execute_task() failed in sas_ata_qc_issue(), and access of ->lldd_task will cause an oops: Call trace: [] sas_ata_post_internal+0x6c/0x150 [] ata_exec_internal_sg+0x32c/0x588 [] ata_exec_internal+0x88/0xe8 [] ata_dev_read_id+0x204/0x5e0 [] ata_dev_reread_id+0x60/0xc8 [] ata_dev_revalidate+0x88/0x1e0 [] ata_eh_recover+0xcf8/0x13a8 [] ata_do_eh+0x5c/0xe0 [] ata_std_error_handler+0x48/0x98 [] ata_scsi_port_error_handler+0x474/0x658 [] async_sas_ata_eh+0x50/0x80 [] async_run_entry_fn+0x64/0x180 [] process_one_work+0x164/0x438 [] worker_thread+0x144/0x4b0 [] kthread+0xfc/0x110 Fix this by reassigning NULL to ->lldd_task in error path. Signed-off-by: Wei Fang Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 935c43095109..596a5450f0eb 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -253,6 +253,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) if (qc->scsicmd) ASSIGN_SAS_TASK(qc->scsicmd, NULL); sas_free_task(task); + qc->lldd_task = NULL; ret = AC_ERR_SYSTEM; }