Home Home > GIT Browse > SLE12-SP5-AZURE
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2017-12-01 16:24:08 +0100
committerJiri Kosina <jkosina@suse.cz>2017-12-01 16:24:08 +0100
commit95da70cf891d7068524b4325e7bb16c92ec93cde (patch)
treeb0813077d6fe721fbb48cf0c4b2e2f375cf6cb4f
parent97f8750d5a29e02c7038c1d80426b1b59a1df2be (diff)
parentb48234dbc664b885167b7116bb21a23011156db4 (diff)
Merge remote-tracking branch 'origin/users/mbrugger/SLE15/for-next' into SLE15rpm-4.12.14-5--SLE-15-Packages-Beta4rpm-4.12.14-5
Conflicts: series.conf
-rw-r--r--config/arm64/default1
-rw-r--r--patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch114
-rw-r--r--patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch300
-rw-r--r--patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch316
-rw-r--r--patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch229
-rw-r--r--patches.drivers/0013-scsi-hisi_sas-add-phy-up-down-bcast-and-channel-ISR.patch345
-rw-r--r--patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch413
-rw-r--r--patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch267
-rw-r--r--patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch119
-rw-r--r--patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch167
-rw-r--r--patches.drivers/0018-scsi-hisi_sas-add-v3-code-for-itct-setup-and-free.patch168
-rw-r--r--patches.drivers/0019-scsi-hisi_sas-add-v3-code-to-send-internal-abort-com.patch90
-rw-r--r--patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch51
-rw-r--r--patches.drivers/0021-scsi-hisi_sas-add-v3-code-to-fill-some-more-hw-funct.patch99
-rw-r--r--patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch143
-rw-r--r--patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch62
-rw-r--r--patches.drivers/hns-remove-useless-void-cast.patch32
-rw-r--r--patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch303
-rw-r--r--patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch64
-rw-r--r--patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch153
-rw-r--r--patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch36
-rw-r--r--patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch35
-rw-r--r--patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch190
-rw-r--r--patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch130
-rw-r--r--patches.drivers/net-hns-set-correct-return-value.patch39
-rw-r--r--patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch149
-rw-r--r--patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch183
-rw-r--r--patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch35
-rw-r--r--patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch543
-rw-r--r--patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch58
-rw-r--r--patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch104
-rw-r--r--patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch81
-rw-r--r--patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch179
-rw-r--r--patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch96
-rw-r--r--patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch335
-rw-r--r--patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch73
-rw-r--r--patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch44
-rw-r--r--patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch78
-rw-r--r--patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch568
-rw-r--r--patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch424
-rw-r--r--patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch43
-rw-r--r--patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch210
-rw-r--r--patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch95
-rw-r--r--patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch105
-rw-r--r--patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch68
-rw-r--r--patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch62
-rw-r--r--patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch123
-rw-r--r--patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch41
-rw-r--r--patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch436
-rw-r--r--patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch148
-rw-r--r--series.conf49
-rw-r--r--supported.conf1
52 files changed, 8197 insertions, 0 deletions
diff --git a/config/arm64/default b/config/arm64/default
index ef6619528d..8d68ac26cb 100644
--- a/config/arm64/default
+++ b/config/arm64/default
@@ -2033,6 +2033,7 @@ CONFIG_AIC79XX_REG_PRETTY_PRINT=y
CONFIG_SCSI_AIC94XX=m
# CONFIG_AIC94XX_DEBUG is not set
CONFIG_SCSI_HISI_SAS=m
+CONFIG_SCSI_HISI_SAS_PCI=m
CONFIG_SCSI_MVSAS=m
# CONFIG_SCSI_MVSAS_DEBUG is not set
CONFIG_SCSI_MVSAS_TASKLET=y
diff --git a/patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch b/patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch
new file mode 100644
index 0000000000..c399d9ef83
--- /dev/null
+++ b/patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch
@@ -0,0 +1,114 @@
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 14 Jun 2017 23:33:19 +0800
+Subject: scsi: hisi_sas: add skeleton v3 hw driver
+Git-commit: 92f61e3bc24a0d42c9ede86ff6f211ef07022dd7
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add skeleton driver for v3 hw in hisi_sas_v3_hw.c
+
+File hisi_sas_v3_hw.c will serve 2 purposes:
+- probing and initialisation of the controller based on pci device
+- hw layer for v3-based controllers
+
+The controller design is quite similar to v2 hw in hip07.
+
+However key differences include:
+-All v2 hw bugs are fixed (hopefully), so workarounds are not required
+-support for device deregistration
+-some interrupt modifications
+-configurable max device support
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/Kconfig | 10 +++++++-
+ drivers/scsi/hisi_sas/Makefile | 1 +
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 47 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 57 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+
+diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
+index 374a329b91fc..d42f29a5eb65 100644
+--- a/drivers/scsi/hisi_sas/Kconfig
++++ b/drivers/scsi/hisi_sas/Kconfig
+@@ -6,4 +6,12 @@ config SCSI_HISI_SAS
+ select BLK_DEV_INTEGRITY
+ depends on ATA
+ help
+- This driver supports HiSilicon's SAS HBA
++ This driver supports HiSilicon's SAS HBA, including support based
++ on platform device
++
++config SCSI_HISI_SAS_PCI
++ tristate "HiSilicon SAS on PCI bus"
++ depends on SCSI_HISI_SAS
++ depends on PCI
++ help
++ This driver supports HiSilicon's SAS HBA based on PCI device
+diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
+index c6d3a1b5fcb9..24623f228510 100644
+--- a/drivers/scsi/hisi_sas/Makefile
++++ b/drivers/scsi/hisi_sas/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
+ obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o hisi_sas_v2_hw.o
++obj-$(CONFIG_SCSI_HISI_SAS_PCI) += hisi_sas_v3_hw.o
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+new file mode 100644
+index 000000000000..cf72577c3e95
+--- /dev/null
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (c) 2017 Hisilicon Limited.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include "hisi_sas.h"
++#define DRV_NAME "hisi_sas_v3_hw"
++
++static int
++hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ return 0;
++}
++
++static void hisi_sas_v3_remove(struct pci_dev *pdev)
++{
++}
++
++enum {
++ /* instances of the controller */
++ hip08,
++};
++
++static const struct pci_device_id sas_v3_pci_table[] = {
++ { PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
++ {}
++};
++
++static struct pci_driver sas_v3_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sas_v3_pci_table,
++ .probe = hisi_sas_v3_probe,
++ .remove = hisi_sas_v3_remove,
++};
++
++module_pci_driver(sas_v3_pci_driver);
++
++MODULE_VERSION(DRV_VERSION);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
++MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");
++MODULE_ALIAS("platform:" DRV_NAME);
+--
+2.14.2
+
diff --git a/patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch b/patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch
new file mode 100644
index 0000000000..8e2ffc08f4
--- /dev/null
+++ b/patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch
@@ -0,0 +1,300 @@
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 14 Jun 2017 23:33:20 +0800
+Subject: scsi: hisi_sas: add initialisation for v3 pci-based controller
+Git-commit: e21fe3a52692f554efd67957c772c702de627a3a
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add the code to initialise the controller which is based on pci device
+in hisi_sas_v3_hw.c
+
+The core controller routines are still in hisi_sas_main.c; some common
+initialisation functions are also exported from hisi_sas_main.c
+
+For pci-based controller, the device properties, like phy count and sas
+address are read from the firmware, same as platform device-based
+controller.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 6 ++
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 18 ++--
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 154 +++++++++++++++++++++++++++++++++
+ 3 files changed, 172 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index c1f6669ab3f8..e89f6aec844f 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -366,6 +366,12 @@ union hisi_sas_command_table {
+ struct hisi_sas_command_table_stp stp;
+ };
+
++extern struct scsi_transport_template *hisi_sas_stt;
++extern struct scsi_host_template *hisi_sas_sht;
++
++extern void hisi_sas_init_add(struct hisi_hba *hisi_hba);
++extern int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost);
++extern void hisi_sas_free(struct hisi_hba *hisi_hba);
+ extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
+ extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
+ extern void hisi_sas_sata_done(struct sas_task *task,
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 8a2af906e1ad..124a3ff569fd 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -1476,9 +1476,10 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
+ }
+ EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology);
+
+-static struct scsi_transport_template *hisi_sas_stt;
++struct scsi_transport_template *hisi_sas_stt;
++EXPORT_SYMBOL_GPL(hisi_sas_stt);
+
+-static struct scsi_host_template hisi_sas_sht = {
++static struct scsi_host_template _hisi_sas_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+@@ -1498,6 +1499,8 @@ static struct scsi_host_template hisi_sas_sht = {
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ };
++struct scsi_host_template *hisi_sas_sht = &_hisi_sas_sht;
++EXPORT_SYMBOL_GPL(hisi_sas_sht);
+
+ static struct sas_domain_function_template hisi_sas_transport_ops = {
+ .lldd_dev_found = hisi_sas_dev_found,
+@@ -1545,7 +1548,7 @@ void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
+ }
+ EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
+
+-static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
++int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+ {
+ struct device *dev = hisi_hba->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+@@ -1664,8 +1667,9 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+ err_out:
+ return -ENOMEM;
+ }
++EXPORT_SYMBOL_GPL(hisi_sas_alloc);
+
+-static void hisi_sas_free(struct hisi_hba *hisi_hba)
++void hisi_sas_free(struct hisi_hba *hisi_hba)
+ {
+ struct device *dev = hisi_hba->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+@@ -1720,6 +1724,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
+ if (hisi_hba->wq)
+ destroy_workqueue(hisi_hba->wq);
+ }
++EXPORT_SYMBOL_GPL(hisi_sas_free);
+
+ static void hisi_sas_rst_work_handler(struct work_struct *work)
+ {
+@@ -1805,7 +1810,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+
+- shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
++ shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
+ if (!shost) {
+ dev_err(dev, "scsi host alloc failed\n");
+ return NULL;
+@@ -1847,7 +1852,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+ return NULL;
+ }
+
+-static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
++void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+ {
+ int i;
+
+@@ -1856,6 +1861,7 @@ static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+ hisi_hba->sas_addr,
+ SAS_ADDR_SIZE);
+ }
++EXPORT_SYMBOL_GPL(hisi_sas_init_add);
+
+ int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index cf72577c3e95..e9a9fb0db370 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -11,14 +11,168 @@
+ #include "hisi_sas.h"
+ #define DRV_NAME "hisi_sas_v3_hw"
+
++static const struct hisi_sas_hw hisi_sas_v3_hw = {
++};
++
++static struct Scsi_Host *
++hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
++{
++ struct Scsi_Host *shost;
++ struct hisi_hba *hisi_hba;
++ struct device *dev = &pdev->dev;
++
++ shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
++ if (!shost)
++ goto err_out;
++ hisi_hba = shost_priv(shost);
++
++ hisi_hba->hw = &hisi_sas_v3_hw;
++ hisi_hba->pci_dev = pdev;
++ hisi_hba->dev = dev;
++ hisi_hba->shost = shost;
++ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
++
++ init_timer(&hisi_hba->timer);
++
++ if (hisi_sas_get_fw_info(hisi_hba) < 0)
++ goto err_out;
++
++ if (hisi_sas_alloc(hisi_hba, shost)) {
++ hisi_sas_free(hisi_hba);
++ goto err_out;
++ }
++
++ return shost;
++err_out:
++ dev_err(dev, "shost alloc failed\n");
++ return NULL;
++}
++
+ static int
+ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
++ struct Scsi_Host *shost;
++ struct hisi_hba *hisi_hba;
++ struct device *dev = &pdev->dev;
++ struct asd_sas_phy **arr_phy;
++ struct asd_sas_port **arr_port;
++ struct sas_ha_struct *sha;
++ int rc, phy_nr, port_nr, i;
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ goto err_out;
++
++ pci_set_master(pdev);
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc)
++ goto err_out_disable_device;
++
++ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
++ (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) {
++ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) ||
++ (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) {
++ dev_err(dev, "No usable DMA addressing method\n");
++ rc = -EIO;
++ goto err_out_regions;
++ }
++ }
++
++ shost = hisi_sas_shost_alloc_pci(pdev);
++ if (!shost) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ sha = SHOST_TO_SAS_HA(shost);
++ hisi_hba = shost_priv(shost);
++ dev_set_drvdata(dev, sha);
++
++ hisi_hba->regs = pcim_iomap(pdev, 5, 0);
++ if (!hisi_hba->regs) {
++ dev_err(dev, "cannot map register.\n");
++ rc = -ENOMEM;
++ goto err_out_ha;
++ }
++
++ phy_nr = port_nr = hisi_hba->n_phy;
++
++ arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
++ arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
++ if (!arr_phy || !arr_port) {
++ rc = -ENOMEM;
++ goto err_out_ha;
++ }
++
++ sha->sas_phy = arr_phy;
++ sha->sas_port = arr_port;
++ sha->core.shost = shost;
++ sha->lldd_ha = hisi_hba;
++
++ shost->transportt = hisi_sas_stt;
++ shost->max_id = HISI_SAS_MAX_DEVICES;
++ shost->max_lun = ~0;
++ shost->max_channel = 1;
++ shost->max_cmd_len = 16;
++ shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
++ shost->can_queue = hisi_hba->hw->max_command_entries;
++ shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
++
++ sha->sas_ha_name = DRV_NAME;
++ sha->dev = dev;
++ sha->lldd_module = THIS_MODULE;
++ sha->sas_addr = &hisi_hba->sas_addr[0];
++ sha->num_phys = hisi_hba->n_phy;
++ sha->core.shost = hisi_hba->shost;
++
++ for (i = 0; i < hisi_hba->n_phy; i++) {
++ sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
++ sha->sas_port[i] = &hisi_hba->port[i].sas_port;
++ }
++
++ hisi_sas_init_add(hisi_hba);
++
++ rc = scsi_add_host(shost, dev);
++ if (rc)
++ goto err_out_ha;
++
++ rc = sas_register_ha(sha);
++ if (rc)
++ goto err_out_register_ha;
++
++ rc = hisi_hba->hw->hw_init(hisi_hba);
++ if (rc)
++ goto err_out_register_ha;
++
++ scsi_scan_host(shost);
++
+ return 0;
++
++err_out_register_ha:
++ scsi_remove_host(shost);
++err_out_ha:
++ kfree(shost);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out_disable_device:
++ pci_disable_device(pdev);
++err_out:
++ return rc;
+ }
+
+ static void hisi_sas_v3_remove(struct pci_dev *pdev)
+ {
++ struct device *dev = &pdev->dev;
++ struct sas_ha_struct *sha = dev_get_drvdata(dev);
++ struct hisi_hba *hisi_hba = sha->lldd_ha;
++
++ sas_unregister_ha(sha);
++ sas_remove_host(sha->core.shost);
++
++ hisi_sas_free(hisi_hba);
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
+ }
+
+ enum {
+--
+2.14.2
+
diff --git a/patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch b/patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch
new file mode 100644
index 0000000000..29744b325f
--- /dev/null
+++ b/patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch
@@ -0,0 +1,316 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:21 +0800
+Subject: scsi: hisi_sas: add v3 hw init
+Git-commit: c94d8ca2b1a810649a20deae54751d94db716042
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to initialise v3 hardware.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 277 +++++++++++++++++++++++++++++++++
+ 1 file changed, 277 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index e9a9fb0db370..1a5eae6bb102 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -11,7 +11,283 @@
+ #include "hisi_sas.h"
+ #define DRV_NAME "hisi_sas_v3_hw"
+
++/* global registers need init*/
++#define DLVRY_QUEUE_ENABLE 0x0
++#define IOST_BASE_ADDR_LO 0x8
++#define IOST_BASE_ADDR_HI 0xc
++#define ITCT_BASE_ADDR_LO 0x10
++#define ITCT_BASE_ADDR_HI 0x14
++#define IO_BROKEN_MSG_ADDR_LO 0x18
++#define IO_BROKEN_MSG_ADDR_HI 0x1c
++#define AXI_AHB_CLK_CFG 0x3c
++#define AXI_USER1 0x48
++#define AXI_USER2 0x4c
++#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
++#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
++#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
++#define SATA_INITI_D2H_STORE_ADDR_HI 0x64
++#define CFG_MAX_TAG 0x68
++#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
++#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
++#define HGC_GET_ITV_TIME 0x90
++#define DEVICE_MSG_WORK_MODE 0x94
++#define OPENA_WT_CONTI_TIME 0x9c
++#define I_T_NEXUS_LOSS_TIME 0xa0
++#define MAX_CON_TIME_LIMIT_TIME 0xa4
++#define BUS_INACTIVE_LIMIT_TIME 0xa8
++#define REJECT_TO_OPEN_LIMIT_TIME 0xac
++#define CFG_AGING_TIME 0xbc
++#define HGC_DFX_CFG2 0xc0
++#define CFG_ABT_SET_QUERY_IPTT 0xd4
++#define CFG_SET_ABORTED_IPTT_OFF 0
++#define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF)
++#define CFG_1US_TIMER_TRSH 0xcc
++#define INT_COAL_EN 0x19c
++#define OQ_INT_COAL_TIME 0x1a0
++#define OQ_INT_COAL_CNT 0x1a4
++#define ENT_INT_COAL_TIME 0x1a8
++#define ENT_INT_COAL_CNT 0x1ac
++#define OQ_INT_SRC 0x1b0
++#define OQ_INT_SRC_MSK 0x1b4
++#define ENT_INT_SRC1 0x1b8
++#define ENT_INT_SRC1_D2H_FIS_CH0_OFF 0
++#define ENT_INT_SRC1_D2H_FIS_CH0_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF)
++#define ENT_INT_SRC1_D2H_FIS_CH1_OFF 8
++#define ENT_INT_SRC1_D2H_FIS_CH1_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF)
++#define ENT_INT_SRC2 0x1bc
++#define ENT_INT_SRC3 0x1c0
++#define ENT_INT_SRC3_WP_DEPTH_OFF 8
++#define ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF 9
++#define ENT_INT_SRC3_RP_DEPTH_OFF 10
++#define ENT_INT_SRC3_AXI_OFF 11
++#define ENT_INT_SRC3_FIFO_OFF 12
++#define ENT_INT_SRC3_LM_OFF 14
++#define ENT_INT_SRC3_ITC_INT_OFF 15
++#define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF)
++#define ENT_INT_SRC3_ABT_OFF 16
++#define ENT_INT_SRC_MSK1 0x1c4
++#define ENT_INT_SRC_MSK2 0x1c8
++#define ENT_INT_SRC_MSK3 0x1cc
++#define CHNL_PHYUPDOWN_INT_MSK 0x1d0
++#define CHNL_ENT_INT_MSK 0x1d4
++#define HGC_COM_INT_MSK 0x1d8
++#define SAS_ECC_INTR 0x1e8
++#define SAS_ECC_INTR_MSK 0x1ec
++#define HGC_ERR_STAT_EN 0x238
++#define DLVRY_Q_0_BASE_ADDR_LO 0x260
++#define DLVRY_Q_0_BASE_ADDR_HI 0x264
++#define DLVRY_Q_0_DEPTH 0x268
++#define DLVRY_Q_0_WR_PTR 0x26c
++#define DLVRY_Q_0_RD_PTR 0x270
++#define HYPER_STREAM_ID_EN_CFG 0xc80
++#define OQ0_INT_SRC_MSK 0xc90
++#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
++#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
++#define COMPL_Q_0_DEPTH 0x4e8
++#define COMPL_Q_0_WR_PTR 0x4ec
++#define COMPL_Q_0_RD_PTR 0x4f0
++#define AWQOS_AWCACHE_CFG 0xc84
++#define ARQOS_ARCACHE_CFG 0xc88
++
++/* phy registers requiring init */
++#define PORT_BASE (0x2000)
++#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
++#define PHY_CTRL (PORT_BASE + 0x14)
++#define PHY_CTRL_RESET_OFF 0
++#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
++#define SL_CFG (PORT_BASE + 0x84)
++#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
++#define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134)
++#define SAS_SMP_CON_TIMER_CFG (PORT_BASE + 0x138)
++#define SAS_STP_CON_TIMER_CFG (PORT_BASE + 0x13c)
++#define CHL_INT0 (PORT_BASE + 0x1b4)
++#define CHL_INT0_HOTPLUG_TOUT_OFF 0
++#define CHL_INT0_HOTPLUG_TOUT_MSK (0x1 << CHL_INT0_HOTPLUG_TOUT_OFF)
++#define CHL_INT0_SL_RX_BCST_ACK_OFF 1
++#define CHL_INT0_SL_RX_BCST_ACK_MSK (0x1 << CHL_INT0_SL_RX_BCST_ACK_OFF)
++#define CHL_INT0_SL_PHY_ENABLE_OFF 2
++#define CHL_INT0_SL_PHY_ENABLE_MSK (0x1 << CHL_INT0_SL_PHY_ENABLE_OFF)
++#define CHL_INT0_NOT_RDY_OFF 4
++#define CHL_INT0_NOT_RDY_MSK (0x1 << CHL_INT0_NOT_RDY_OFF)
++#define CHL_INT0_PHY_RDY_OFF 5
++#define CHL_INT0_PHY_RDY_MSK (0x1 << CHL_INT0_PHY_RDY_OFF)
++#define CHL_INT1 (PORT_BASE + 0x1b8)
++#define CHL_INT1_DMAC_TX_ECC_ERR_OFF 15
++#define CHL_INT1_DMAC_TX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
++#define CHL_INT1_DMAC_RX_ECC_ERR_OFF 17
++#define CHL_INT1_DMAC_RX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
++#define CHL_INT2 (PORT_BASE + 0x1bc)
++#define CHL_INT0_MSK (PORT_BASE + 0x1c0)
++#define CHL_INT1_MSK (PORT_BASE + 0x1c4)
++#define CHL_INT2_MSK (PORT_BASE + 0x1c8)
++#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
++#define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
++#define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
++#define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
++#define PHYCTRL_PHY_ENA_MSK (PORT_BASE + 0x2bc)
++#define SL_RX_BCAST_CHK_MSK (PORT_BASE + 0x2c0)
++#define PHYCTRL_OOB_RESTART_MSK (PORT_BASE + 0x2c4)
++
++struct hisi_sas_complete_v3_hdr {
++ __le32 dw0;
++ __le32 dw1;
++ __le32 act;
++ __le32 dw3;
++};
++
++#define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
++
++static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
++{
++ void __iomem *regs = hisi_hba->regs + off;
++
++ writel(val, regs);
++}
++
++static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
++ u32 off, u32 val)
++{
++ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
++
++ writel(val, regs);
++}
++
++static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
++{
++ int i;
++
++ /* Global registers init */
++ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
++ (u32)((1ULL << hisi_hba->queue_count) - 1));
++ hisi_sas_write32(hisi_hba, AXI_USER1, 0x0);
++ hisi_sas_write32(hisi_hba, AXI_USER2, 0x40000060);
++ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
++ hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0xd);
++ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
++ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
++ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
++ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffff);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff);
++ hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
++ hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0);
++ hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0);
++ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
++ hisi_sas_write32(hisi_hba, AWQOS_AWCACHE_CFG, 0xf0f0);
++ hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
++ for (i = 0; i < hisi_hba->queue_count; i++)
++ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
++
++ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
++ hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
++ hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff07fff);
++
++ for (i = 0; i < hisi_hba->n_phy; i++) {
++ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x801);
++ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
++ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
++ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
++ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
++ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
++ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
++ hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x83f801fc);
++ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
++ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199b4fa);
++ hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG,
++ 0xa0064);
++ hisi_sas_phy_write32(hisi_hba, i, SAS_STP_CON_TIMER_CFG,
++ 0xa0064);
++ }
++ for (i = 0; i < hisi_hba->queue_count; i++) {
++ /* Delivery queue */
++ hisi_sas_write32(hisi_hba,
++ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
++ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
++
++ hisi_sas_write32(hisi_hba, DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
++ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
++
++ hisi_sas_write32(hisi_hba, DLVRY_Q_0_DEPTH + (i * 0x14),
++ HISI_SAS_QUEUE_SLOTS);
++
++ /* Completion queue */
++ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
++ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
++
++ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
++ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
++
++ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
++ HISI_SAS_QUEUE_SLOTS);
++ }
++
++ /* itct */
++ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
++ lower_32_bits(hisi_hba->itct_dma));
++
++ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
++ upper_32_bits(hisi_hba->itct_dma));
++
++ /* iost */
++ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
++ lower_32_bits(hisi_hba->iost_dma));
++
++ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
++ upper_32_bits(hisi_hba->iost_dma));
++
++ /* breakpoint */
++ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_LO,
++ lower_32_bits(hisi_hba->breakpoint_dma));
++
++ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_HI,
++ upper_32_bits(hisi_hba->breakpoint_dma));
++
++ /* SATA broken msg */
++ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_LO,
++ lower_32_bits(hisi_hba->sata_breakpoint_dma));
++
++ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_HI,
++ upper_32_bits(hisi_hba->sata_breakpoint_dma));
++
++ /* SATA initial fis */
++ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_LO,
++ lower_32_bits(hisi_hba->initial_fis_dma));
++
++ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
++ upper_32_bits(hisi_hba->initial_fis_dma));
++}
++
++static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
++{
++ init_reg_v3_hw(hisi_hba);
++
++ return 0;
++}
++
++static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
++{
++ int rc;
++
++ rc = hw_init_v3_hw(hisi_hba);
++ if (rc)
++ return rc;
++
++ return 0;
++}
++
+ static const struct hisi_sas_hw hisi_sas_v3_hw = {
++ .hw_init = hisi_sas_v3_init,
++ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
++ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+ };
+
+ static struct Scsi_Host *
+@@ -175,6 +451,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
+ pci_disable_device(pdev);
+ }
+
++
+ enum {
+ /* instances of the controller */
+ hip08,
+--
+2.14.2
+
diff --git a/patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch b/patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch
new file mode 100644
index 0000000000..8d3bbb88fa
--- /dev/null
+++ b/patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch
@@ -0,0 +1,229 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:22 +0800
+Subject: scsi: hisi_sas: add v3 hw PHY init
+Git-commit: 3975f6054e31c55c7e73faa342780e2af2f30872
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to configure PHYs for v3 hw.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 127 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 126 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 1a5eae6bb102..558025013624 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -19,6 +19,10 @@
+ #define ITCT_BASE_ADDR_HI 0x14
+ #define IO_BROKEN_MSG_ADDR_LO 0x18
+ #define IO_BROKEN_MSG_ADDR_HI 0x1c
++#define PHY_CONTEXT 0x20
++#define PHY_STATE 0x24
++#define PHY_PORT_NUM_MA 0x28
++#define PHY_CONN_RATE 0x30
+ #define AXI_AHB_CLK_CFG 0x3c
+ #define AXI_USER1 0x48
+ #define AXI_USER2 0x4c
+@@ -42,6 +46,7 @@
+ #define CFG_SET_ABORTED_IPTT_OFF 0
+ #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF)
+ #define CFG_1US_TIMER_TRSH 0xcc
++#define CHNL_INT_STATUS 0x148
+ #define INT_COAL_EN 0x19c
+ #define OQ_INT_COAL_TIME 0x1a0
+ #define OQ_INT_COAL_CNT 0x1a4
+@@ -68,9 +73,11 @@
+ #define ENT_INT_SRC_MSK1 0x1c4
+ #define ENT_INT_SRC_MSK2 0x1c8
+ #define ENT_INT_SRC_MSK3 0x1cc
++#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31
+ #define CHNL_PHYUPDOWN_INT_MSK 0x1d0
+ #define CHNL_ENT_INT_MSK 0x1d4
+ #define HGC_COM_INT_MSK 0x1d8
++#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
+ #define SAS_ECC_INTR 0x1e8
+ #define SAS_ECC_INTR_MSK 0x1ec
+ #define HGC_ERR_STAT_EN 0x238
+@@ -91,11 +98,33 @@
+
+ /* phy registers requiring init */
+ #define PORT_BASE (0x2000)
++#define PHY_CFG (PORT_BASE + 0x0)
++#define HARD_PHY_LINKRATE (PORT_BASE + 0x4)
++#define PHY_CFG_ENA_OFF 0
++#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
++#define PHY_CFG_DC_OPT_OFF 2
++#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+ #define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
+ #define PHY_CTRL (PORT_BASE + 0x14)
+ #define PHY_CTRL_RESET_OFF 0
+ #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+ #define SL_CFG (PORT_BASE + 0x84)
++#define SL_CONTROL (PORT_BASE + 0x94)
++#define SL_CONTROL_NOTIFY_EN_OFF 0
++#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
++#define SL_CTA_OFF 17
++#define SL_CTA_MSK (0x1 << SL_CTA_OFF)
++#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
++#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
++#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
++#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
++#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
++#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
++#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
++#define TXID_AUTO (PORT_BASE + 0xb8)
++#define CT3_OFF 1
++#define CT3_MSK (0x1 << CT3_OFF)
++#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+ #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+ #define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134)
+ #define SAS_SMP_CON_TIMER_CFG (PORT_BASE + 0x138)
+@@ -136,6 +165,13 @@ struct hisi_sas_complete_v3_hdr {
+ };
+
+ #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
++#define HISI_SAS_MSI_COUNT_V3_HW 32
++
++enum {
++ HISI_SAS_PHY_PHY_UPDOWN,
++ HISI_SAS_PHY_CHNL_INT,
++ HISI_SAS_PHY_INT_NR
++};
+
+ static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
+ {
+@@ -152,6 +188,14 @@ static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
+ writel(val, regs);
+ }
+
++static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
++ int phy_no, u32 off)
++{
++ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
++
++ return readl(regs);
++}
++
+ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ int i;
+@@ -266,6 +310,45 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
+ upper_32_bits(hisi_hba->initial_fis_dma));
+ }
+
++static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
++
++ cfg &= ~PHY_CFG_DC_OPT_MSK;
++ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
++}
++
++static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ struct sas_identify_frame identify_frame;
++ u32 *identify_buffer;
++
++ memset(&identify_frame, 0, sizeof(identify_frame));
++ identify_frame.dev_type = SAS_END_DEVICE;
++ identify_frame.frame_type = 0;
++ identify_frame._un1 = 1;
++ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
++ identify_frame.target_bits = SAS_PROTOCOL_NONE;
++ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
++ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
++ identify_frame.phy_id = phy_no;
++ identify_buffer = (u32 *)(&identify_frame);
++
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
++ __swab32(identify_buffer[0]));
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
++ __swab32(identify_buffer[1]));
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
++ __swab32(identify_buffer[2]));
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
++ __swab32(identify_buffer[3]));
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
++ __swab32(identify_buffer[4]));
++ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
++ __swab32(identify_buffer[5]));
++}
++
+ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ init_reg_v3_hw(hisi_hba);
+@@ -273,6 +356,47 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
+ return 0;
+ }
+
++static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
++
++ cfg |= PHY_CFG_ENA_MSK;
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
++}
++
++static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ config_id_frame_v3_hw(hisi_hba, phy_no);
++ config_phy_opt_mode_v3_hw(hisi_hba, phy_no);
++ enable_phy_v3_hw(hisi_hba, phy_no);
++}
++
++static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
++{
++ int i;
++
++ for (i = 0; i < hisi_hba->n_phy; i++)
++ start_phy_v3_hw(hisi_hba, i);
++}
++
++static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
++{
++ start_phys_v3_hw(hisi_hba);
++}
++
++static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ u32 sl_control;
++
++ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
++ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
++ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
++ msleep(1);
++ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
++ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
++ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
++}
++
+ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
+ {
+ int rc;
+@@ -288,6 +412,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .hw_init = hisi_sas_v3_init,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
++ .sl_notify = sl_notify_v3_hw,
++ .phys_init = phys_init_v3_hw,
+ };
+
+ static struct Scsi_Host *
+@@ -451,7 +577,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
+ pci_disable_device(pdev);
+ }
+
+-
+ enum {
+ /* instances of the controller */
+ hip08,
+--
+2.14.2
+
diff --git a/patches.drivers/0013-scsi-hisi_sas-add-phy-up-down-bcast-and-channel-ISR.patch b/patches.drivers/0013-scsi-hisi_sas-add-phy-up-down-bcast-and-channel-ISR.patch
new file mode 100644
index 0000000000..474fa17bf3
--- /dev/null
+++ b/patches.drivers/0013-scsi-hisi_sas-add-phy-up-down-bcast-and-channel-ISR.patch
@@ -0,0 +1,345 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:23 +0800
+Subject: scsi: hisi_sas: add phy up/down/bcast and channel ISR
+Git-commit: 54edeee1e1f3621632308212daf383ed6688e955
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to initialise interrupts and add some interrupt handlers.
+
+Also add function hisi_sas_v3_destroy_irqs() to clean-up irqs upon
+module unloading.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 283 +++++++++++++++++++++++++++++++++
+ 1 file changed, 283 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 558025013624..3065252499c4 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -173,6 +173,13 @@ enum {
+ HISI_SAS_PHY_INT_NR
+ };
+
++static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
++{
++ void __iomem *regs = hisi_hba->regs + off;
++
++ return readl(regs);
++}
++
+ static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
+ {
+ void __iomem *regs = hisi_hba->regs + off;
+@@ -397,6 +404,269 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ }
+
++static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
++{
++ int i, res = 0;
++ u32 context, port_id, link_rate, hard_phy_linkrate;
++ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
++ struct asd_sas_phy *sas_phy = &phy->sas_phy;
++ struct device *dev = hisi_hba->dev;
++
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
++
++ port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
++ port_id = (port_id >> (4 * phy_no)) & 0xf;
++ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
++ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
++
++ if (port_id == 0xf) {
++ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
++ res = IRQ_NONE;
++ goto end;
++ }
++ sas_phy->linkrate = link_rate;
++ hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
++ HARD_PHY_LINKRATE);
++ phy->maximum_linkrate = hard_phy_linkrate & 0xf;
++ phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
++ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
++
++ /* Check for SATA dev */
++ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
++ if (context & (1 << phy_no)) {
++ struct hisi_sas_initial_fis *initial_fis;
++ struct dev_to_host_fis *fis;
++ u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
++
++ dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
++ initial_fis = &hisi_hba->initial_fis[phy_no];
++ fis = &initial_fis->fis;
++ sas_phy->oob_mode = SATA_OOB_MODE;
++ attached_sas_addr[0] = 0x50;
++ attached_sas_addr[7] = phy_no;
++ memcpy(sas_phy->attached_sas_addr,
++ attached_sas_addr,
++ SAS_ADDR_SIZE);
++ memcpy(sas_phy->frame_rcvd, fis,
++ sizeof(struct dev_to_host_fis));
++ phy->phy_type |= PORT_TYPE_SATA;
++ phy->identify.device_type = SAS_SATA_DEV;
++ phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
++ phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
++ } else {
++ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
++ struct sas_identify_frame *id =
++ (struct sas_identify_frame *)frame_rcvd;
++
++ dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
++ for (i = 0; i < 6; i++) {
++ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
++ RX_IDAF_DWORD0 + (i * 4));
++ frame_rcvd[i] = __swab32(idaf);
++ }
++ sas_phy->oob_mode = SAS_OOB_MODE;
++ memcpy(sas_phy->attached_sas_addr,
++ &id->sas_addr,
++ SAS_ADDR_SIZE);
++ phy->phy_type |= PORT_TYPE_SAS;
++ phy->identify.device_type = id->dev_type;
++ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
++ if (phy->identify.device_type == SAS_END_DEVICE)
++ phy->identify.target_port_protocols =
++ SAS_PROTOCOL_SSP;
++ else if (phy->identify.device_type != SAS_PHY_UNUSED)
++ phy->identify.target_port_protocols =
++ SAS_PROTOCOL_SMP;
++ }
++
++ phy->port_id = port_id;
++ phy->phy_attached = 1;
++ queue_work(hisi_hba->wq, &phy->phyup_ws);
++
++end:
++ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
++ CHL_INT0_SL_PHY_ENABLE_MSK);
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
++
++ return res;
++}
++
++static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
++{
++ int res = 0;
++ u32 phy_state, sl_ctrl, txid_auto;
++ struct device *dev = hisi_hba->dev;
++
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
++
++ phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
++ dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
++ hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
++
++ sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
++ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL,
++ sl_ctrl&(~SL_CTA_MSK));
++
++ txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
++ hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
++ txid_auto | CT3_MSK);
++
++ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
++
++ return res;
++}
++
++static void phy_bcast_v3_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;
++
++ hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
++ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
++ 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);
++}
++
++static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p)
++{
++ struct hisi_hba *hisi_hba = p;
++ u32 irq_msk;
++ int phy_no = 0;
++ irqreturn_t res = IRQ_NONE;
++
++ irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
++ & 0x11111111;
++ while (irq_msk) {
++ if (irq_msk & 1) {
++ u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no,
++ CHL_INT0);
++ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
++ int rdy = phy_state & (1 << phy_no);
++
++ if (rdy) {
++ if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK)
++ /* phy up */
++ if (phy_up_v3_hw(phy_no, hisi_hba)
++ == IRQ_HANDLED)
++ res = IRQ_HANDLED;
++ if (irq_value & CHL_INT0_SL_RX_BCST_ACK_MSK)
++ /* phy bcast */
++ phy_bcast_v3_hw(phy_no, hisi_hba);
++ } else {
++ if (irq_value & CHL_INT0_NOT_RDY_MSK)
++ /* phy down */
++ if (phy_down_v3_hw(phy_no, hisi_hba)
++ == IRQ_HANDLED)
++ res = IRQ_HANDLED;
++ }
++ }
++ irq_msk >>= 4;
++ phy_no++;
++ }
++
++ return res;
++}
++
++static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
++{
++ struct hisi_hba *hisi_hba = p;
++ struct device *dev = hisi_hba->dev;
++ u32 ent_msk, ent_tmp, irq_msk;
++ int phy_no = 0;
++
++ ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
++ ent_tmp = ent_msk;
++ ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK;
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk);
++
++ irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
++ & 0xeeeeeeee;
++
++ while (irq_msk) {
++ u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
++ CHL_INT0);
++ u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
++ CHL_INT1);
++ u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
++ CHL_INT2);
++
++ if ((irq_msk & (4 << (phy_no * 4))) &&
++ irq_value1) {
++ if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
++ CHL_INT1_DMAC_TX_ECC_ERR_MSK))
++ panic("%s: DMAC RX/TX ecc bad error! (0x%x)",
++ dev_name(dev), irq_value1);
++
++ hisi_sas_phy_write32(hisi_hba, phy_no,
++ CHL_INT1, irq_value1);
++ }
++
++ if (irq_msk & (8 << (phy_no * 4)) && irq_value2)
++ hisi_sas_phy_write32(hisi_hba, phy_no,
++ CHL_INT2, irq_value2);
++
++
++ if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
++ hisi_sas_phy_write32(hisi_hba, phy_no,
++ CHL_INT0, irq_value0
++ & (~CHL_INT0_HOTPLUG_TOUT_MSK)
++ & (~CHL_INT0_SL_PHY_ENABLE_MSK)
++ & (~CHL_INT0_NOT_RDY_MSK));
++ }
++ irq_msk &= ~(0xe << (phy_no * 4));
++ phy_no++;
++ }
++
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
++
++ return IRQ_HANDLED;
++}
++
++static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
++{
++ struct device *dev = hisi_hba->dev;
++ struct pci_dev *pdev = hisi_hba->pci_dev;
++ int vectors, rc;
++ int max_msi = HISI_SAS_MSI_COUNT_V3_HW;
++
++ vectors = pci_alloc_irq_vectors(hisi_hba->pci_dev, 1,
++ max_msi, PCI_IRQ_MSI);
++ if (vectors < max_msi) {
++ dev_err(dev, "could not allocate all msi (%d)\n", vectors);
++ return -ENOENT;
++ }
++
++ rc = devm_request_irq(dev, pci_irq_vector(pdev, 1),
++ int_phy_up_down_bcast_v3_hw, 0,
++ DRV_NAME " phy", hisi_hba);
++ if (rc) {
++ dev_err(dev, "could not request phy interrupt, rc=%d\n", rc);
++ rc = -ENOENT;
++ goto free_irq_vectors;
++ }
++
++ rc = devm_request_irq(dev, pci_irq_vector(pdev, 2),
++ int_chnl_int_v3_hw, 0,
++ DRV_NAME " channel", hisi_hba);
++ if (rc) {
++ dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc);
++ rc = -ENOENT;
++ goto free_phy_irq;
++ }
++
++
++ return 0;
++
++free_phy_irq:
++ free_irq(pci_irq_vector(pdev, 1), hisi_hba);
++free_irq_vectors:
++ pci_free_irq_vectors(pdev);
++ return rc;
++}
++
+ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
+ {
+ int rc;
+@@ -405,6 +675,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
+ if (rc)
+ return rc;
+
++ rc = interrupt_init_v3_hw(hisi_hba);
++ if (rc)
++ return rc;
++
+ return 0;
+ }
+
+@@ -563,6 +837,14 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return rc;
+ }
+
++static void
++hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba)
++{
++ free_irq(pci_irq_vector(pdev, 1), hisi_hba);
++ free_irq(pci_irq_vector(pdev, 2), hisi_hba);
++ pci_free_irq_vectors(pdev);
++}
++
+ static void hisi_sas_v3_remove(struct pci_dev *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -573,6 +855,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
+ sas_remove_host(sha->core.shost);
+
+ hisi_sas_free(hisi_hba);
++ hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ }
+--
+2.14.2
+
diff --git a/patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch b/patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch
new file mode 100644
index 0000000000..b46561f144
--- /dev/null
+++ b/patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch
@@ -0,0 +1,413 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:24 +0800
+Subject: scsi: hisi_sas: add v3 cq interrupt handler
+Git-commit: 60b4a5ee90349a50fc7e199d3dd37dfd7e2c51a5
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add v3 cq interrupt handler slot_complete_v3_hw().
+
+Note: The slot error handling needs to be further refined in the future
+to examine all fields in the error record, and handle appropriately,
+instead of current solution - just report SAS_OPEN_REJECT.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 340 +++++++++++++++++++++++++++++++++
+ 1 file changed, 340 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 3065252499c4..4869b73e0284 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -157,6 +157,32 @@
+ #define SL_RX_BCAST_CHK_MSK (PORT_BASE + 0x2c0)
+ #define PHYCTRL_OOB_RESTART_MSK (PORT_BASE + 0x2c4)
+
++/* Completion header */
++/* dw0 */
++#define CMPLT_HDR_CMPLT_OFF 0
++#define CMPLT_HDR_CMPLT_MSK (0x3 << CMPLT_HDR_CMPLT_OFF)
++#define CMPLT_HDR_ERROR_PHASE_OFF 2
++#define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF)
++#define CMPLT_HDR_RSPNS_XFRD_OFF 10
++#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
++#define CMPLT_HDR_ERX_OFF 12
++#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF)
++#define CMPLT_HDR_ABORT_STAT_OFF 13
++#define CMPLT_HDR_ABORT_STAT_MSK (0x7 << CMPLT_HDR_ABORT_STAT_OFF)
++/* abort_stat */
++#define STAT_IO_NOT_VALID 0x1
++#define STAT_IO_NO_DEVICE 0x2
++#define STAT_IO_COMPLETE 0x3
++#define STAT_IO_ABORTED 0x4
++/* dw1 */
++#define CMPLT_HDR_IPTT_OFF 0
++#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
++#define CMPLT_HDR_DEV_ID_OFF 16
++#define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF)
++/* dw3 */
++#define CMPLT_HDR_IO_IN_TARGET_OFF 17
++#define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF)
++
+ struct hisi_sas_complete_v3_hdr {
+ __le32 dw0;
+ __le32 dw1;
+@@ -164,6 +190,24 @@ struct hisi_sas_complete_v3_hdr {
+ __le32 dw3;
+ };
+
++struct hisi_sas_err_record_v3 {
++ /* dw0 */
++ __le32 trans_tx_fail_type;
++
++ /* dw1 */
++ __le32 trans_rx_fail_type;
++
++ /* dw2 */
++ __le16 dma_tx_err_type;
++ __le16 sipc_rx_err_type;
++
++ /* dw3 */
++ __le32 dma_rx_err_type;
++};
++
++#define RX_DATA_LEN_UNDERFLOW_OFF 6
++#define RX_DATA_LEN_UNDERFLOW_MSK (1 << RX_DATA_LEN_UNDERFLOW_OFF)
++
+ #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
+ #define HISI_SAS_MSI_COUNT_V3_HW 32
+
+@@ -625,11 +669,275 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
+ return IRQ_HANDLED;
+ }
+
++static void
++slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
++ struct hisi_sas_slot *slot)
++{
++ struct task_status_struct *ts = &task->task_status;
++ struct hisi_sas_complete_v3_hdr *complete_queue =
++ hisi_hba->complete_hdr[slot->cmplt_queue];
++ struct hisi_sas_complete_v3_hdr *complete_hdr =
++ &complete_queue[slot->cmplt_queue_slot];
++ struct hisi_sas_err_record_v3 *record = slot->status_buffer;
++ u32 dma_rx_err_type = record->dma_rx_err_type;
++ u32 trans_tx_fail_type = record->trans_tx_fail_type;
++
++ switch (task->task_proto) {
++ case SAS_PROTOCOL_SSP:
++ if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
++ ts->residual = trans_tx_fail_type;
++ ts->stat = SAS_DATA_UNDERRUN;
++ } else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
++ ts->stat = SAS_QUEUE_FULL;
++ slot->abort = 1;
++ } else {
++ ts->stat = SAS_OPEN_REJECT;
++ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
++ }
++ break;
++ case SAS_PROTOCOL_SATA:
++ case SAS_PROTOCOL_STP:
++ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
++ if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
++ ts->residual = trans_tx_fail_type;
++ ts->stat = SAS_DATA_UNDERRUN;
++ } else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
++ ts->stat = SAS_PHY_DOWN;
++ slot->abort = 1;
++ } else {
++ ts->stat = SAS_OPEN_REJECT;
++ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
++ }
++ hisi_sas_sata_done(task, slot);
++ break;
++ case SAS_PROTOCOL_SMP:
++ ts->stat = SAM_STAT_CHECK_CONDITION;
++ break;
++ default:
++ break;
++ }
++}
++
++static int
++slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
++{
++ struct sas_task *task = slot->task;
++ struct hisi_sas_device *sas_dev;
++ struct device *dev = hisi_hba->dev;
++ struct task_status_struct *ts;
++ struct domain_device *device;
++ enum exec_status sts;
++ struct hisi_sas_complete_v3_hdr *complete_queue =
++ hisi_hba->complete_hdr[slot->cmplt_queue];
++ struct hisi_sas_complete_v3_hdr *complete_hdr =
++ &complete_queue[slot->cmplt_queue_slot];
++ int aborted;
++ unsigned long flags;
++
++ if (unlikely(!task || !task->lldd_task || !task->dev))
++ return -EINVAL;
++
++ ts = &task->task_status;
++ device = task->dev;
++ sas_dev = device->lldd_dev;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
++ task->task_state_flags &=
++ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ memset(ts, 0, sizeof(*ts));
++ ts->resp = SAS_TASK_COMPLETE;
++ if (unlikely(aborted)) {
++ ts->stat = SAS_ABORTED_TASK;
++ hisi_sas_slot_task_free(hisi_hba, task, slot);
++ return -1;
++ }
++
++ if (unlikely(!sas_dev)) {
++ dev_dbg(dev, "slot complete: port has not device\n");
++ ts->stat = SAS_PHY_DOWN;
++ goto out;
++ }
++
++ /*
++ * Use SAS+TMF status codes
++ */
++ switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK)
++ >> CMPLT_HDR_ABORT_STAT_OFF) {
++ case STAT_IO_ABORTED:
++ /* this IO has been aborted by abort command */
++ ts->stat = SAS_ABORTED_TASK;
++ goto out;
++ case STAT_IO_COMPLETE:
++ /* internal abort command complete */
++ ts->stat = TMF_RESP_FUNC_SUCC;
++ goto out;
++ case STAT_IO_NO_DEVICE:
++ ts->stat = TMF_RESP_FUNC_COMPLETE;
++ goto out;
++ case STAT_IO_NOT_VALID:
++ /*
++ * abort single IO, the controller can't find the IO
++ */
++ ts->stat = TMF_RESP_FUNC_FAILED;
++ goto out;
++ default:
++ break;
++ }
++
++ /* check for erroneous completion */
++ if ((complete_hdr->dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
++ slot_err_v3_hw(hisi_hba, task, slot);
++ if (unlikely(slot->abort))
++ return ts->stat;
++ goto out;
++ }
++
++ switch (task->task_proto) {
++ case SAS_PROTOCOL_SSP: {
++ struct ssp_response_iu *iu = slot->status_buffer +
++ sizeof(struct hisi_sas_err_record);
++
++ sas_ssp_task_response(dev, task, iu);
++ break;
++ }
++ case SAS_PROTOCOL_SMP: {
++ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
++ void *to;
++
++ ts->stat = SAM_STAT_GOOD;
++ to = kmap_atomic(sg_page(sg_resp));
++
++ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
++ DMA_FROM_DEVICE);
++ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
++ DMA_TO_DEVICE);
++ memcpy(to + sg_resp->offset,
++ slot->status_buffer +
++ sizeof(struct hisi_sas_err_record),
++ sg_dma_len(sg_resp));
++ kunmap_atomic(to);
++ break;
++ }
++ case SAS_PROTOCOL_SATA:
++ case SAS_PROTOCOL_STP:
++ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
++ ts->stat = SAM_STAT_GOOD;
++ hisi_sas_sata_done(task, slot);
++ break;
++ default:
++ ts->stat = SAM_STAT_CHECK_CONDITION;
++ break;
++ }
++
++ if (!slot->port->port_attached) {
++ dev_err(dev, "slot complete: port %d has removed\n",
++ slot->port->sas_port.id);
++ ts->stat = SAS_PHY_DOWN;
++ }
++
++out:
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ task->task_state_flags |= SAS_TASK_STATE_DONE;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ spin_lock_irqsave(&hisi_hba->lock, flags);
++ hisi_sas_slot_task_free(hisi_hba, task, slot);
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
++ sts = ts->stat;
++
++ if (task->task_done)
++ task->task_done(task);
++
++ return sts;
++}
++
++static void cq_tasklet_v3_hw(unsigned long val)
++{
++ struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
++ struct hisi_hba *hisi_hba = cq->hisi_hba;
++ struct hisi_sas_slot *slot;
++ struct hisi_sas_itct *itct;
++ struct hisi_sas_complete_v3_hdr *complete_queue;
++ u32 rd_point = cq->rd_point, wr_point, dev_id;
++ int queue = cq->id;
++ struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
++
++ complete_queue = hisi_hba->complete_hdr[queue];
++
++ spin_lock(&dq->lock);
++ wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
++ (0x14 * queue));
++
++ while (rd_point != wr_point) {
++ struct hisi_sas_complete_v3_hdr *complete_hdr;
++ int iptt;
++
++ complete_hdr = &complete_queue[rd_point];
++
++ /* Check for NCQ completion */
++ if (complete_hdr->act) {
++ u32 act_tmp = complete_hdr->act;
++ int ncq_tag_count = ffs(act_tmp);
++
++ dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
++ CMPLT_HDR_DEV_ID_OFF;
++ itct = &hisi_hba->itct[dev_id];
++
++ /* The NCQ tags are held in the itct header */
++ while (ncq_tag_count) {
++ __le64 *ncq_tag = &itct->qw4_15[0];
++
++ ncq_tag_count -= 1;
++ iptt = (ncq_tag[ncq_tag_count / 5]
++ >> (ncq_tag_count % 5) * 12) & 0xfff;
++
++ slot = &hisi_hba->slot_info[iptt];
++ slot->cmplt_queue_slot = rd_point;
++ slot->cmplt_queue = queue;
++ slot_complete_v3_hw(hisi_hba, slot);
++
++ act_tmp &= ~(1 << ncq_tag_count);
++ ncq_tag_count = ffs(act_tmp);
++ }
++ } else {
++ iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
++ slot = &hisi_hba->slot_info[iptt];
++ slot->cmplt_queue_slot = rd_point;
++ slot->cmplt_queue = queue;
++ slot_complete_v3_hw(hisi_hba, slot);
++ }
++
++ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
++ rd_point = 0;
++ }
++
++ /* update rd_point */
++ cq->rd_point = rd_point;
++ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
++ spin_unlock(&dq->lock);
++}
++
++static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
++{
++ struct hisi_sas_cq *cq = p;
++ struct hisi_hba *hisi_hba = cq->hisi_hba;
++ int queue = cq->id;
++
++ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
++
++ tasklet_schedule(&cq->tasklet);
++
++ return IRQ_HANDLED;
++}
++
+ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ struct device *dev = hisi_hba->dev;
+ struct pci_dev *pdev = hisi_hba->pci_dev;
+ int vectors, rc;
++ int i, k;
+ int max_msi = HISI_SAS_MSI_COUNT_V3_HW;
+
+ vectors = pci_alloc_irq_vectors(hisi_hba->pci_dev, 1,
+@@ -657,9 +965,34 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
+ goto free_phy_irq;
+ }
+
++ /* Init tasklets for cq only */
++ for (i = 0; i < hisi_hba->queue_count; i++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
++ struct tasklet_struct *t = &cq->tasklet;
++
++ rc = devm_request_irq(dev, pci_irq_vector(pdev, i+16),
++ cq_interrupt_v3_hw, 0,
++ DRV_NAME " cq", cq);
++ if (rc) {
++ dev_err(dev,
++ "could not request cq%d interrupt, rc=%d\n",
++ i, rc);
++ rc = -ENOENT;
++ goto free_cq_irqs;
++ }
++
++ tasklet_init(t, cq_tasklet_v3_hw, (unsigned long)cq);
++ }
+
+ return 0;
+
++free_cq_irqs:
++ for (k = 0; k < i; k++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[k];
++
++ free_irq(pci_irq_vector(pdev, k+16), cq);
++ }
++ free_irq(pci_irq_vector(pdev, 2), hisi_hba);
+ free_phy_irq:
+ free_irq(pci_irq_vector(pdev, 1), hisi_hba);
+ free_irq_vectors:
+@@ -840,8 +1173,15 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ static void
+ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba)
+ {
++ int i;
++
+ free_irq(pci_irq_vector(pdev, 1), hisi_hba);
+ free_irq(pci_irq_vector(pdev, 2), hisi_hba);
++ for (i = 0; i < hisi_hba->queue_count; i++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
++
++ free_irq(pci_irq_vector(pdev, i+16), cq);
++ }
+ pci_free_irq_vectors(pdev);
+ }
+
+--
+2.14.2
+
diff --git a/patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch b/patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch
new file mode 100644
index 0000000000..d127a706bc
--- /dev/null
+++ b/patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch
@@ -0,0 +1,267 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:25 +0800
+Subject: scsi: hisi_sas: add v3 code to send SSP frame
+Git-commit: a2204723acefd504561b5dbc53d9c0a1c2528eab
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to prepare SSP frame and deliver it to hardware.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 208 +++++++++++++++++++++++++++++++++
+ 1 file changed, 208 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 4869b73e0284..c869aca273aa 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -157,6 +157,41 @@
+ #define SL_RX_BCAST_CHK_MSK (PORT_BASE + 0x2c0)
+ #define PHYCTRL_OOB_RESTART_MSK (PORT_BASE + 0x2c4)
+
++/* HW dma structures */
++/* Delivery queue header */
++/* dw0 */
++#define CMD_HDR_RESP_REPORT_OFF 5
++#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
++#define CMD_HDR_TLR_CTRL_OFF 6
++#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
++#define CMD_HDR_PORT_OFF 18
++#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
++#define CMD_HDR_PRIORITY_OFF 27
++#define CMD_HDR_PRIORITY_MSK (0x1 << CMD_HDR_PRIORITY_OFF)
++#define CMD_HDR_CMD_OFF 29
++#define CMD_HDR_CMD_MSK (0x7 << CMD_HDR_CMD_OFF)
++/* dw1 */
++#define CMD_HDR_DIR_OFF 5
++#define CMD_HDR_DIR_MSK (0x3 << CMD_HDR_DIR_OFF)
++#define CMD_HDR_VDTL_OFF 10
++#define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF)
++#define CMD_HDR_FRAME_TYPE_OFF 11
++#define CMD_HDR_FRAME_TYPE_MSK (0x1f << CMD_HDR_FRAME_TYPE_OFF)
++#define CMD_HDR_DEV_ID_OFF 16
++#define CMD_HDR_DEV_ID_MSK (0xffff << CMD_HDR_DEV_ID_OFF)
++/* dw2 */
++#define CMD_HDR_CFL_OFF 0
++#define CMD_HDR_CFL_MSK (0x1ff << CMD_HDR_CFL_OFF)
++#define CMD_HDR_MRFL_OFF 15
++#define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF)
++#define CMD_HDR_SG_MOD_OFF 24
++#define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
++/* dw6 */
++#define CMD_HDR_DIF_SGL_LEN_OFF 0
++#define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
++#define CMD_HDR_DATA_SGL_LEN_OFF 16
++#define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
++
+ /* Completion header */
+ /* dw0 */
+ #define CMPLT_HDR_CMPLT_OFF 0
+@@ -217,6 +252,11 @@ enum {
+ HISI_SAS_PHY_INT_NR
+ };
+
++#define DIR_NO_DATA 0
++#define DIR_TO_INI 1
++#define DIR_TO_DEVICE 2
++#define DIR_RESERVED 3
++
+ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+ {
+ void __iomem *regs = hisi_hba->regs + off;
+@@ -224,6 +264,13 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+ return readl(regs);
+ }
+
++static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
++{
++ void __iomem *regs = hisi_hba->regs + off;
++
++ return readl_relaxed(regs);
++}
++
+ static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
+ {
+ void __iomem *regs = hisi_hba->regs + off;
+@@ -448,6 +495,163 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ }
+
++/**
++ * The callpath to this function and upto writing the write
++ * queue pointer should be safe from interruption.
++ */
++static int
++get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
++{
++ struct device *dev = hisi_hba->dev;
++ int queue = dq->id;
++ u32 r, w;
++
++ w = dq->wr_point;
++ r = hisi_sas_read32_relaxed(hisi_hba,
++ DLVRY_Q_0_RD_PTR + (queue * 0x14));
++ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
++ dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
++ queue, r, w);
++ return -EAGAIN;
++ }
++
++ return 0;
++}
++
++static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
++{
++ struct hisi_hba *hisi_hba = dq->hisi_hba;
++ int dlvry_queue = dq->slot_prep->dlvry_queue;
++ int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
++
++ dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
++ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
++ dq->wr_point);
++}
++
++static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_slot *slot,
++ struct hisi_sas_cmd_hdr *hdr,
++ struct scatterlist *scatter,
++ int n_elem)
++{
++ struct device *dev = hisi_hba->dev;
++ struct scatterlist *sg;
++ int i;
++
++ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
++ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
++ n_elem);
++ return -EINVAL;
++ }
++
++ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
++ &slot->sge_page_dma);
++ if (!slot->sge_page)
++ return -ENOMEM;
++
++ for_each_sg(scatter, sg, n_elem, i) {
++ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
++
++ entry->addr = cpu_to_le64(sg_dma_address(sg));
++ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
++ entry->data_len = cpu_to_le32(sg_dma_len(sg));
++ entry->data_off = 0;
++ }
++
++ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
++ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
++
++ return 0;
++}
++
++static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_slot *slot, int is_tmf,
++ struct hisi_sas_tmf_task *tmf)
++{
++ struct sas_task *task = slot->task;
++ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
++ struct domain_device *device = task->dev;
++ struct hisi_sas_device *sas_dev = device->lldd_dev;
++ struct hisi_sas_port *port = slot->port;
++ struct sas_ssp_task *ssp_task = &task->ssp_task;
++ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
++ int has_data = 0, rc, priority = is_tmf;
++ u8 *buf_cmd;
++ u32 dw1 = 0, dw2 = 0;
++
++ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
++ (2 << CMD_HDR_TLR_CTRL_OFF) |
++ (port->id << CMD_HDR_PORT_OFF) |
++ (priority << CMD_HDR_PRIORITY_OFF) |
++ (1 << CMD_HDR_CMD_OFF)); /* ssp */
++
++ dw1 = 1 << CMD_HDR_VDTL_OFF;
++ if (is_tmf) {
++ dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
++ dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
++ } else {
++ dw1 |= 1 << CMD_HDR_FRAME_TYPE_OFF;
++ switch (scsi_cmnd->sc_data_direction) {
++ case DMA_TO_DEVICE:
++ has_data = 1;
++ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
++ break;
++ case DMA_FROM_DEVICE:
++ has_data = 1;
++ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
++ break;
++ default:
++ dw1 &= ~CMD_HDR_DIR_MSK;
++ }
++ }
++
++ /* map itct entry */
++ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
++ hdr->dw1 = cpu_to_le32(dw1);
++
++ dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
++ + 3) / 4) << CMD_HDR_CFL_OFF) |
++ ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) |
++ (2 << CMD_HDR_SG_MOD_OFF);
++ hdr->dw2 = cpu_to_le32(dw2);
++ hdr->transfer_tags = cpu_to_le32(slot->idx);
++
++ if (has_data) {
++ rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
++ slot->n_elem);
++ if (rc)
++ return rc;
++ }
++
++ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
++ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
++ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++
++ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
++ memcpy(buf_cmd, ssp_task->LUN, 8);
++
++ if (!is_tmf) {
++ buf_cmd[9] = ssp_task->task_attr | (ssp_task->task_prio << 3);
++ memcpy(buf_cmd + 12, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
++ } else {
++ buf_cmd[10] = tmf->tmf;
++ switch (tmf->tmf) {
++ case TMF_ABORT_TASK:
++ case TMF_QUERY_TASK:
++ buf_cmd[12] =
++ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
++ buf_cmd[13] =
++ tmf->tag_of_task_to_be_managed & 0xff;
++ break;
++ default:
++ break;
++ }
++ }
++
++ return 0;
++}
++
+ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+ {
+ int i, res = 0;
+@@ -1020,6 +1224,10 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+ .sl_notify = sl_notify_v3_hw,
++ .prep_ssp = prep_ssp_v3_hw,
++ .get_free_slot = get_free_slot_v3_hw,
++ .start_delivery = start_delivery_v3_hw,
++ .slot_complete = slot_complete_v3_hw,
+ .phys_init = phys_init_v3_hw,
+ };
+
+--
+2.14.2
+
diff --git a/patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch b/patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch
new file mode 100644
index 0000000000..7273e4f255
--- /dev/null
+++ b/patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch
@@ -0,0 +1,119 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:26 +0800
+Subject: scsi: hisi_sas: add v3 code to send SMP frame
+Git-commit: fa913de23aa2e7443ff34a61eadab37b6b20797d
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to prepare SMP frame.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 74 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index c869aca273aa..515f50c4032c 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -186,6 +186,9 @@
+ #define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF)
+ #define CMD_HDR_SG_MOD_OFF 24
+ #define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
++/* dw3 */
++#define CMD_HDR_IPTT_OFF 0
++#define CMD_HDR_IPTT_MSK (0xffff << CMD_HDR_IPTT_OFF)
+ /* dw6 */
+ #define CMD_HDR_DIF_SGL_LEN_OFF 0
+ #define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
+@@ -652,6 +655,76 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
+ return 0;
+ }
+
++static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_slot *slot)
++{
++ struct sas_task *task = slot->task;
++ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
++ struct domain_device *device = task->dev;
++ struct device *dev = hisi_hba->dev;
++ struct hisi_sas_port *port = slot->port;
++ struct scatterlist *sg_req, *sg_resp;
++ struct hisi_sas_device *sas_dev = device->lldd_dev;
++ dma_addr_t req_dma_addr;
++ unsigned int req_len, resp_len;
++ int elem, rc;
++
++ /*
++ * DMA-map SMP request, response buffers
++ */
++ /* req */
++ sg_req = &task->smp_task.smp_req;
++ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
++ if (!elem)
++ return -ENOMEM;
++ req_len = sg_dma_len(sg_req);
++ req_dma_addr = sg_dma_address(sg_req);
++
++ /* resp */
++ sg_resp = &task->smp_task.smp_resp;
++ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
++ if (!elem) {
++ rc = -ENOMEM;
++ goto err_out_req;
++ }
++ resp_len = sg_dma_len(sg_resp);
++ if ((req_len & 0x3) || (resp_len & 0x3)) {
++ rc = -EINVAL;
++ goto err_out_resp;
++ }
++
++ /* create header */
++ /* dw0 */
++ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
++ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
++ (2 << CMD_HDR_CMD_OFF)); /* smp */
++
++ /* map itct entry */
++ hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) |
++ (1 << CMD_HDR_FRAME_TYPE_OFF) |
++ (DIR_NO_DATA << CMD_HDR_DIR_OFF));
++
++ /* dw2 */
++ hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) |
++ (HISI_SAS_MAX_SMP_RESP_SZ / 4 <<
++ CMD_HDR_MRFL_OFF));
++
++ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
++
++ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
++ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++
++ return 0;
++
++err_out_resp:
++ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
++ DMA_FROM_DEVICE);
++err_out_req:
++ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
++ DMA_TO_DEVICE);
++ return rc;
++}
++
+ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+ {
+ int i, res = 0;
+@@ -1225,6 +1298,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+ .sl_notify = sl_notify_v3_hw,
+ .prep_ssp = prep_ssp_v3_hw,
++ .prep_smp = prep_smp_v3_hw,
+ .get_free_slot = get_free_slot_v3_hw,
+ .start_delivery = start_delivery_v3_hw,
+ .slot_complete = slot_complete_v3_hw,
+--
+2.14.2
+
diff --git a/patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch b/patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch
new file mode 100644
index 0000000000..5fdaed5bc2
--- /dev/null
+++ b/patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch
@@ -0,0 +1,167 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:27 +0800
+Subject: scsi: hisi_sas: add v3 code to send ATA frame
+Git-commit: ce60689e12ddfee94afaaa23089e1131f892839a
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to prepare ATA frame for v3 hw
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 106 +++++++++++++++++++++++++++++++++
+ 1 file changed, 106 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 515f50c4032c..30c103b20d88 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -171,8 +171,11 @@
+ #define CMD_HDR_CMD_OFF 29
+ #define CMD_HDR_CMD_MSK (0x7 << CMD_HDR_CMD_OFF)
+ /* dw1 */
++#define CMD_HDR_UNCON_CMD_OFF 3
+ #define CMD_HDR_DIR_OFF 5
+ #define CMD_HDR_DIR_MSK (0x3 << CMD_HDR_DIR_OFF)
++#define CMD_HDR_RESET_OFF 7
++#define CMD_HDR_RESET_MSK (0x1 << CMD_HDR_RESET_OFF)
+ #define CMD_HDR_VDTL_OFF 10
+ #define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF)
+ #define CMD_HDR_FRAME_TYPE_OFF 11
+@@ -182,6 +185,8 @@
+ /* dw2 */
+ #define CMD_HDR_CFL_OFF 0
+ #define CMD_HDR_CFL_MSK (0x1ff << CMD_HDR_CFL_OFF)
++#define CMD_HDR_NCQ_TAG_OFF 10
++#define CMD_HDR_NCQ_TAG_MSK (0x1f << CMD_HDR_NCQ_TAG_OFF)
+ #define CMD_HDR_MRFL_OFF 15
+ #define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF)
+ #define CMD_HDR_SG_MOD_OFF 24
+@@ -260,6 +265,11 @@ enum {
+ #define DIR_TO_DEVICE 2
+ #define DIR_RESERVED 3
+
++#define CMD_IS_UNCONSTRAINT(cmd) \
++ ((cmd == ATA_CMD_READ_LOG_EXT) || \
++ (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \
++ (cmd == ATA_CMD_DEV_RESET))
++
+ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+ {
+ void __iomem *regs = hisi_hba->regs + off;
+@@ -725,6 +735,101 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
+ return rc;
+ }
+
++static int get_ncq_tag_v3_hw(struct sas_task *task, u32 *tag)
++{
++ struct ata_queued_cmd *qc = task->uldd_task;
++
++ if (qc) {
++ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
++ qc->tf.command == ATA_CMD_FPDMA_READ) {
++ *tag = qc->tag;
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_slot *slot)
++{
++ struct sas_task *task = slot->task;
++ struct domain_device *device = task->dev;
++ struct domain_device *parent_dev = device->parent;
++ struct hisi_sas_device *sas_dev = device->lldd_dev;
++ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
++ struct asd_sas_port *sas_port = device->port;
++ struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
++ u8 *buf_cmd;
++ int has_data = 0, rc = 0, hdr_tag = 0;
++ u32 dw1 = 0, dw2 = 0;
++
++ hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
++ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
++ hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
++ else
++ hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
++
++ switch (task->data_dir) {
++ case DMA_TO_DEVICE:
++ has_data = 1;
++ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
++ break;
++ case DMA_FROM_DEVICE:
++ has_data = 1;
++ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
++ break;
++ default:
++ dw1 &= ~CMD_HDR_DIR_MSK;
++ }
++
++ if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) &&
++ (task->ata_task.fis.control & ATA_SRST))
++ dw1 |= 1 << CMD_HDR_RESET_OFF;
++
++ dw1 |= (hisi_sas_get_ata_protocol(
++ task->ata_task.fis.command, task->data_dir))
++ << CMD_HDR_FRAME_TYPE_OFF;
++ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
++
++ if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command))
++ dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF;
++
++ hdr->dw1 = cpu_to_le32(dw1);
++
++ /* dw2 */
++ if (task->ata_task.use_ncq && get_ncq_tag_v3_hw(task, &hdr_tag)) {
++ task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
++ dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
++ }
++
++ dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF |
++ 2 << CMD_HDR_SG_MOD_OFF;
++ hdr->dw2 = cpu_to_le32(dw2);
++
++ /* dw3 */
++ hdr->transfer_tags = cpu_to_le32(slot->idx);
++
++ if (has_data) {
++ rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
++ slot->n_elem);
++ if (rc)
++ return rc;
++ }
++
++ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
++ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
++ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++
++ buf_cmd = slot->command_table;
++
++ if (likely(!task->ata_task.device_control_reg_update))
++ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
++ /* fill in command FIS */
++ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
++
++ return 0;
++}
++
+ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+ {
+ int i, res = 0;
+@@ -1299,6 +1404,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .sl_notify = sl_notify_v3_hw,
+ .prep_ssp = prep_ssp_v3_hw,
+ .prep_smp = prep_smp_v3_hw,
++ .prep_stp = prep_ata_v3_hw,
+ .get_free_slot = get_free_slot_v3_hw,
+ .start_delivery = start_delivery_v3_hw,
+ .slot_complete = slot_complete_v3_hw,
+--
+2.14.2
+
diff --git a/patches.drivers/0018-scsi-hisi_sas-add-v3-code-for-itct-setup-and-free.patch b/patches.drivers/0018-scsi-hisi_sas-add-v3-code-for-itct-setup-and-free.patch
new file mode 100644
index 0000000000..b95a8cdc9a
--- /dev/null
+++ b/patches.drivers/0018-scsi-hisi_sas-add-v3-code-for-itct-setup-and-free.patch
@@ -0,0 +1,168 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:28 +0800
+Subject: scsi: hisi_sas: add v3 code for itct setup and free
+Git-commit: 182e7222ebe0e638f8e22a1ad6724e8d128e96f2
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to itct setup and free for v3 hw.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 114 +++++++++++++++++++++++++++++++++
+ 1 file changed, 114 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 30c103b20d88..b9ab24d2fc57 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -24,6 +24,11 @@
+ #define PHY_PORT_NUM_MA 0x28
+ #define PHY_CONN_RATE 0x30
+ #define AXI_AHB_CLK_CFG 0x3c
++#define ITCT_CLR 0x44
++#define ITCT_CLR_EN_OFF 16
++#define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF)
++#define ITCT_DEV_OFF 0
++#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF)
+ #define AXI_USER1 0x48
+ #define AXI_USER2 0x4c
+ #define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
+@@ -226,6 +231,26 @@
+ #define CMPLT_HDR_IO_IN_TARGET_OFF 17
+ #define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF)
+
++/* ITCT header */
++/* qw0 */
++#define ITCT_HDR_DEV_TYPE_OFF 0
++#define ITCT_HDR_DEV_TYPE_MSK (0x3 << ITCT_HDR_DEV_TYPE_OFF)
++#define ITCT_HDR_VALID_OFF 2
++#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF)
++#define ITCT_HDR_MCR_OFF 5
++#define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF)
++#define ITCT_HDR_VLN_OFF 9
++#define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF)
++#define ITCT_HDR_SMP_TIMEOUT_OFF 16
++#define ITCT_HDR_AWT_CONTINUE_OFF 25
++#define ITCT_HDR_PORT_ID_OFF 28
++#define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF)
++/* qw2 */
++#define ITCT_HDR_INLT_OFF 0
++#define ITCT_HDR_INLT_MSK (0xffffULL << ITCT_HDR_INLT_OFF)
++#define ITCT_HDR_RTOLT_OFF 48
++#define ITCT_HDR_RTOLT_MSK (0xffffULL << ITCT_HDR_RTOLT_OFF)
++
+ struct hisi_sas_complete_v3_hdr {
+ __le32 dw0;
+ __le32 dw1;
+@@ -460,6 +485,93 @@ static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ __swab32(identify_buffer[5]));
+ }
+
++static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_device *sas_dev)
++{
++ struct domain_device *device = sas_dev->sas_device;
++ struct device *dev = hisi_hba->dev;
++ u64 qw0, device_id = sas_dev->device_id;
++ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
++ struct domain_device *parent_dev = device->parent;
++ struct asd_sas_port *sas_port = device->port;
++ struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
++
++ memset(itct, 0, sizeof(*itct));
++
++ /* qw0 */
++ qw0 = 0;
++ switch (sas_dev->dev_type) {
++ case SAS_END_DEVICE:
++ case SAS_EDGE_EXPANDER_DEVICE:
++ case SAS_FANOUT_EXPANDER_DEVICE:
++ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
++ break;
++ case SAS_SATA_DEV:
++ case SAS_SATA_PENDING:
++ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
++ qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
++ else
++ qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
++ break;
++ default:
++ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
++ sas_dev->dev_type);
++ }
++
++ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
++ (device->linkrate << ITCT_HDR_MCR_OFF) |
++ (1 << ITCT_HDR_VLN_OFF) |
++ (0xfa << ITCT_HDR_SMP_TIMEOUT_OFF) |
++ (1 << ITCT_HDR_AWT_CONTINUE_OFF) |
++ (port->id << ITCT_HDR_PORT_ID_OFF));
++ itct->qw0 = cpu_to_le64(qw0);
++
++ /* qw1 */
++ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
++ itct->sas_addr = __swab64(itct->sas_addr);
++
++ /* qw2 */
++ if (!dev_is_sata(device))
++ itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) |
++ (0x1ULL << ITCT_HDR_RTOLT_OFF));
++}
++
++static void free_device_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_device *sas_dev)
++{
++ u64 dev_id = sas_dev->device_id;
++ struct device *dev = hisi_hba->dev;
++ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
++ u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
++
++ /* clear the itct interrupt state */
++ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
++ ENT_INT_SRC3_ITC_INT_MSK);
++
++ /* clear the itct table*/
++ reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
++ reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
++ hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
++
++ udelay(10);
++ reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
++ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
++ dev_dbg(dev, "got clear ITCT done interrupt\n");
++
++ /* invalid the itct state*/
++ memset(itct, 0, sizeof(struct hisi_sas_itct));
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
++ ENT_INT_SRC3_ITC_INT_MSK);
++ hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED;
++ hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL;
++
++ /* clear the itct */
++ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
++ dev_dbg(dev, "clear ITCT ok\n");
++ }
++}
++
+ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ init_reg_v3_hw(hisi_hba);
+@@ -1399,8 +1511,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
+
+ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .hw_init = hisi_sas_v3_init,
++ .setup_itct = setup_itct_v3_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
++ .free_device = free_device_v3_hw,
+ .sl_notify = sl_notify_v3_hw,
+ .prep_ssp = prep_ssp_v3_hw,
+ .prep_smp = prep_smp_v3_hw,
+--
+2.14.2
+
diff --git a/patches.drivers/0019-scsi-hisi_sas-add-v3-code-to-send-internal-abort-com.patch b/patches.drivers/0019-scsi-hisi_sas-add-v3-code-to-send-internal-abort-com.patch
new file mode 100644
index 0000000000..9b9faf549b
--- /dev/null
+++ b/patches.drivers/0019-scsi-hisi_sas-add-v3-code-to-send-internal-abort-com.patch
@@ -0,0 +1,90 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:29 +0800
+Subject: scsi: hisi_sas: add v3 code to send internal abort command
+Git-commit: 4de0ca69e58d26c9038d4d4c290f3ed6a24a897a
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to prepare internal abort command.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 38 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index b9ab24d2fc57..ef5c15817181 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -165,6 +165,10 @@
+ /* HW dma structures */
+ /* Delivery queue header */
+ /* dw0 */
++#define CMD_HDR_ABORT_FLAG_OFF 0
++#define CMD_HDR_ABORT_FLAG_MSK (0x3 << CMD_HDR_ABORT_FLAG_OFF)
++#define CMD_HDR_ABORT_DEVICE_TYPE_OFF 2
++#define CMD_HDR_ABORT_DEVICE_TYPE_MSK (0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF)
+ #define CMD_HDR_RESP_REPORT_OFF 5
+ #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
+ #define CMD_HDR_TLR_CTRL_OFF 6
+@@ -204,6 +208,11 @@
+ #define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
+ #define CMD_HDR_DATA_SGL_LEN_OFF 16
+ #define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
++/* dw7 */
++#define CMD_HDR_ADDR_MODE_SEL_OFF 15
++#define CMD_HDR_ADDR_MODE_SEL_MSK (1 << CMD_HDR_ADDR_MODE_SEL_OFF)
++#define CMD_HDR_ABORT_IPTT_OFF 16
++#define CMD_HDR_ABORT_IPTT_MSK (0xffff << CMD_HDR_ABORT_IPTT_OFF)
+
+ /* Completion header */
+ /* dw0 */
+@@ -942,6 +951,34 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
+ return 0;
+ }
+
++static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
++ struct hisi_sas_slot *slot,
++ int device_id, int abort_flag, int tag_to_abort)
++{
++ struct sas_task *task = slot->task;
++ struct domain_device *dev = task->dev;
++ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
++ struct hisi_sas_port *port = slot->port;
++
++ /* dw0 */
++ hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
++ (port->id << CMD_HDR_PORT_OFF) |
++ ((dev_is_sata(dev) ? 1:0)
++ << CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
++ (abort_flag
++ << CMD_HDR_ABORT_FLAG_OFF));
++
++ /* dw1 */
++ hdr->dw1 = cpu_to_le32(device_id
++ << CMD_HDR_DEV_ID_OFF);
++
++ /* dw7 */
++ hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
++ hdr->transfer_tags = cpu_to_le32(slot->idx);
++
++ return 0;
++}
++
+ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+ {
+ int i, res = 0;
+@@ -1519,6 +1556,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .prep_ssp = prep_ssp_v3_hw,
+ .prep_smp = prep_smp_v3_hw,
+ .prep_stp = prep_ata_v3_hw,
++ .prep_abort = prep_abort_v3_hw,
+ .get_free_slot = get_free_slot_v3_hw,
+ .start_delivery = start_delivery_v3_hw,
+ .slot_complete = slot_complete_v3_hw,
+--
+2.14.2
+
diff --git a/patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch b/patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch
new file mode 100644
index 0000000000..b0a41bccae
--- /dev/null
+++ b/patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch
@@ -0,0 +1,51 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:30 +0800
+Subject: scsi: hisi_sas: add get_wideport_bitmap_v3_hw()
+Git-commit: f771d3b08fe0e3ee9ac0226cc8f9d7930eb925da
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code for interface get_wideport_bitmap.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index ef5c15817181..3cd4b9a77e22 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -629,6 +629,18 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ }
+
++static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id)
++{
++ int i, bitmap = 0;
++ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
++
++ for (i = 0; i < hisi_hba->n_phy; i++)
++ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
++ bitmap |= 1 << i;
++
++ return bitmap;
++}
++
+ /**
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+@@ -1550,6 +1562,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .hw_init = hisi_sas_v3_init,
+ .setup_itct = setup_itct_v3_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
++ .get_wideport_bitmap = get_wideport_bitmap_v3_hw,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+ .free_device = free_device_v3_hw,
+ .sl_notify = sl_notify_v3_hw,
+--
+2.14.2
+
diff --git a/patches.drivers/0021-scsi-hisi_sas-add-v3-code-to-fill-some-more-hw-funct.patch b/patches.drivers/0021-scsi-hisi_sas-add-v3-code-to-fill-some-more-hw-funct.patch
new file mode 100644
index 0000000000..fe015e6b92
--- /dev/null
+++ b/patches.drivers/0021-scsi-hisi_sas-add-v3-code-to-fill-some-more-hw-funct.patch
@@ -0,0 +1,99 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:31 +0800
+Subject: scsi: hisi_sas: add v3 code to fill some more hw function pointers
+Git-commit: 402cd9f0ae9eefcdf9b6c0c87aadc32faec086ff
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add code to fill the interface of phy_hard_reset, phy_get_max_linkrate,
+and phy enable/disable.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 39 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 3cd4b9a77e22..cf1eb472c404 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -129,6 +129,8 @@
+ #define TXID_AUTO (PORT_BASE + 0xb8)
+ #define CT3_OFF 1
+ #define CT3_MSK (0x1 << CT3_OFF)
++#define TX_HARDRST_OFF 2
++#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF)
+ #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+ #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+ #define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134)
+@@ -596,6 +598,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+ }
+
++static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
++
++ cfg &= ~PHY_CFG_ENA_MSK;
++ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
++}
++
+ static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ {
+ config_id_frame_v3_hw(hisi_hba, phy_no);
+@@ -603,6 +613,11 @@ static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+ enable_phy_v3_hw(hisi_hba, phy_no);
+ }
+
++static void stop_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ disable_phy_v3_hw(hisi_hba, phy_no);
++}
++
+ static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ int i;
+@@ -611,6 +626,26 @@ static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
+ start_phy_v3_hw(hisi_hba, i);
+ }
+
++static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
++ u32 txid_auto;
++
++ stop_phy_v3_hw(hisi_hba, phy_no);
++ if (phy->identify.device_type == SAS_END_DEVICE) {
++ txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
++ hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
++ txid_auto | TX_HARDRST_MSK);
++ }
++ msleep(100);
++ start_phy_v3_hw(hisi_hba, phy_no);
++}
++
++enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
++{
++ return SAS_LINK_RATE_12_0_GBPS;
++}
++
+ static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ start_phys_v3_hw(hisi_hba);
+@@ -1574,6 +1609,10 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .start_delivery = start_delivery_v3_hw,
+ .slot_complete = slot_complete_v3_hw,
+ .phys_init = phys_init_v3_hw,
++ .phy_enable = enable_phy_v3_hw,
++ .phy_disable = disable_phy_v3_hw,
++ .phy_hard_reset = phy_hard_reset_v3_hw,
++ .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw,
+ };
+
+ static struct Scsi_Host *
+--
+2.14.2
+
diff --git a/patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch b/patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch
new file mode 100644
index 0000000000..495327d0ca
--- /dev/null
+++ b/patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch
@@ -0,0 +1,143 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:32 +0800
+Subject: scsi: hisi_sas: modify internal abort dev flow for v3 hw
+Git-commit: d30ff2632333dab794d3be14e16ca8c42dfc294d
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+There is a change for abort dev for v3 hw: add registers to configure
+unaborted iptt for a device, and then inform this to logic.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 2 ++
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++++++++++++++
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 28 ++++++++++++++++++++++++++++
+ 3 files changed, 45 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index e89f6aec844f..4fc23087a939 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -188,6 +188,8 @@ struct hisi_sas_hw {
+ void (*free_device)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *dev);
+ int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
++ void (*dereg_device)(struct hisi_hba *hisi_hba,
++ struct domain_device *device);
+ int (*soft_reset)(struct hisi_hba *hisi_hba);
+ int max_command_entries;
+ int complete_hdr_size;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 124a3ff569fd..e2f8d928e579 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -727,6 +727,13 @@ static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
+ }
+ }
+
++static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
++ struct domain_device *device)
++{
++ if (hisi_hba->hw->dereg_device)
++ hisi_hba->hw->dereg_device(hisi_hba, device);
++}
++
+ static void hisi_sas_dev_gone(struct domain_device *device)
+ {
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+@@ -740,6 +747,8 @@ static void hisi_sas_dev_gone(struct domain_device *device)
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_DEV, 0);
+
++ hisi_sas_dereg_device(hisi_hba, device);
++
+ hisi_hba->hw->free_device(hisi_hba, sas_dev);
+ device->lldd_dev = NULL;
+ memset(sas_dev, 0, sizeof(*sas_dev));
+@@ -1071,6 +1080,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
+ if (task->dev->dev_type == SAS_SATA_DEV) {
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_DEV, 0);
++ hisi_sas_dereg_device(hisi_hba, device);
+ rc = hisi_sas_softreset_ata_disk(device);
+ }
+ } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
+@@ -1137,6 +1147,10 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
+ return TMF_RESP_FUNC_FAILED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+
++ hisi_sas_internal_task_abort(hisi_hba, device,
++ HISI_SAS_INT_ABT_DEV, 0);
++ hisi_sas_dereg_device(hisi_hba, device);
++
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+@@ -1164,6 +1178,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+ HISI_SAS_INT_ABT_DEV, 0);
+ if (rc == TMF_RESP_FUNC_FAILED)
+ goto out;
++ hisi_sas_dereg_device(hisi_hba, device);
+
+ phy = sas_get_local_phy(device);
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index cf1eb472c404..c998b81f33de 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -50,6 +50,10 @@
+ #define CFG_ABT_SET_QUERY_IPTT 0xd4
+ #define CFG_SET_ABORTED_IPTT_OFF 0
+ #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF)
++#define CFG_SET_ABORTED_EN_OFF 12
++#define CFG_ABT_SET_IPTT_DONE 0xd8
++#define CFG_ABT_SET_IPTT_DONE_OFF 0
++#define HGC_IOMB_PROC1_STATUS 0x104
+ #define CFG_1US_TIMER_TRSH 0xcc
+ #define CHNL_INT_STATUS 0x148
+ #define INT_COAL_EN 0x19c
+@@ -583,6 +587,29 @@ static void free_device_v3_hw(struct hisi_hba *hisi_hba,
+ }
+ }
+
++static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
++ struct domain_device *device)
++{
++ struct hisi_sas_slot *slot, *slot2;
++ struct hisi_sas_device *sas_dev = device->lldd_dev;
++ u32 cfg_abt_set_query_iptt;
++
++ cfg_abt_set_query_iptt = hisi_sas_read32(hisi_hba,
++ CFG_ABT_SET_QUERY_IPTT);
++ list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry) {
++ cfg_abt_set_query_iptt &= ~CFG_SET_ABORTED_IPTT_MSK;
++ cfg_abt_set_query_iptt |= (1 << CFG_SET_ABORTED_EN_OFF) |
++ (slot->idx << CFG_SET_ABORTED_IPTT_OFF);
++ hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
++ cfg_abt_set_query_iptt);
++ }
++ cfg_abt_set_query_iptt &= ~(1 << CFG_SET_ABORTED_EN_OFF);
++ hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
++ cfg_abt_set_query_iptt);
++ hisi_sas_write32(hisi_hba, CFG_ABT_SET_IPTT_DONE,
++ 1 << CFG_ABT_SET_IPTT_DONE_OFF);
++}
++
+ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+ init_reg_v3_hw(hisi_hba);
+@@ -1613,6 +1640,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
+ .phy_disable = disable_phy_v3_hw,
+ .phy_hard_reset = phy_hard_reset_v3_hw,
+ .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw,
++ .dereg_device = dereg_device_v3_hw,
+ };
+
+ static struct Scsi_Host *
+--
+2.14.2
+
diff --git a/patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch b/patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch
new file mode 100644
index 0000000000..943930febd
--- /dev/null
+++ b/patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch
@@ -0,0 +1,62 @@
+From: Ding Tianhong <dingtianhong@huawei.com>
+Date: Thu, 10 Aug 2017 10:52:45 +0800
+Subject: clocksource/drivers/arm_arch_timer: Avoid infinite recursion when
+ ftrace is enabled
+Git-commit: adb4f11e0a8f4e29900adb2b7af28b6bbd5c1fa4
+Patch-mainline: v4.13-rc6
+References: bsc#1068693
+
+On platforms with an arch timer erratum workaround, it's possible for
+arch_timer_reg_read_stable() to recurse into itself when certain
+tracing options are enabled, leading to stack overflows and related
+problems.
+
+For example, when PREEMPT_TRACER and FUNCTION_GRAPH_TRACER are
+selected, it's possible to trigger this with:
+
+$ mount -t debugfs nodev /sys/kernel/debug/
+$ echo function_graph > /sys/kernel/debug/tracing/current_tracer
+
+The problem is that in such cases, preempt_disable() instrumentation
+attempts to acquire a timestamp via trace_clock(), resulting in a call
+back to arch_timer_reg_read_stable(), and hence recursion.
+
+This patch changes arch_timer_reg_read_stable() to use
+preempt_{disable,enable}_notrace(), which avoids this.
+
+This problem is similar to the fixed by upstream commit 96b3d28bf4
+("sched/clock: Prevent tracing recursion in sched_clock_cpu()").
+
+Fixes: 6acc71ccac71 ("arm64: arch_timer: Allows a CPU-specific erratum to only affect a subset of CPUs")
+Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ arch/arm64/include/asm/arch_timer.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
+index 74d08e44a651..a652ce0a5cb2 100644
+--- a/arch/arm64/include/asm/arch_timer.h
++++ b/arch/arm64/include/asm/arch_timer.h
+@@ -65,13 +65,13 @@ DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
+ u64 _val; \
+ if (needs_unstable_timer_counter_workaround()) { \
+ const struct arch_timer_erratum_workaround *wa; \
+- preempt_disable(); \
++ preempt_disable_notrace(); \
+ wa = __this_cpu_read(timer_unstable_counter_workaround); \
+ if (wa && wa->read_##reg) \
+ _val = wa->read_##reg(); \
+ else \
+ _val = read_sysreg(reg); \
+- preempt_enable(); \
++ preempt_enable_notrace(); \
+ } else { \
+ _val = read_sysreg(reg); \
+ } \
+--
+2.14.2
+
diff --git a/patches.drivers/hns-remove-useless-void-cast.patch b/patches.drivers/hns-remove-useless-void-cast.patch
new file mode 100644
index 0000000000..7fe46147f8
--- /dev/null
+++ b/patches.drivers/hns-remove-useless-void-cast.patch
@@ -0,0 +1,32 @@
+From: stephen hemminger <stephen@networkplumber.org>
+Date: Tue, 18 Jul 2017 15:59:26 -0700
+Subject: hns: remove useless void cast
+Git-commit: 4a614dd3e550b66a2e57119e2d5e0fbc7f17f634
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+There is no need to cast away return value of dev_close.
+
+Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+index a8db27e86a11..78cb20c67aa6 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+@@ -595,7 +595,7 @@ static void hns_nic_self_test(struct net_device *ndev,
+ set_bit(NIC_STATE_TESTING, &priv->state);
+
+ if (if_running)
+- (void)dev_close(ndev);
++ dev_close(ndev);
+
+ for (i = 0; i < SELF_TEST_TPYE_NUM; i++) {
+ if (!st_param[i][1])
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch b/patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch
new file mode 100644
index 0000000000..832011de4b
--- /dev/null
+++ b/patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch
@@ -0,0 +1,303 @@
+From: Lin Yun Sheng <linyunsheng@huawei.com>
+Date: Wed, 2 Aug 2017 17:57:37 +0800
+Subject: net: hns: Add self-adaptive interrupt coalesce support in hns driver
+Git-commit: b8c17f7088310e7ee34ca61929f737045adfd449
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+When deal with low and high throughput, it is hard to achiece both
+high performance and low latency. In order to achiece that, this patch
+calculates the rx rate, and adjust the interrupt coalesce parameter
+accordingly.
+
+Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
+Tested-by: Weiwei Deng <dengweiwei@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hnae.c | 1 +
+ drivers/net/ethernet/hisilicon/hns/hnae.h | 15 +++
+ drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 1 +
+ drivers/net/ethernet/hisilicon/hns/hns_enet.c | 134 ++++++++++++++++++++--
+ drivers/net/ethernet/hisilicon/hns/hns_enet.h | 2 +-
+ drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 7 +-
+ 6 files changed, 149 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c
+index 9d9b6e6dd988..a051e582d541 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hnae.c
++++ b/drivers/net/ethernet/hisilicon/hns/hnae.c
+@@ -202,6 +202,7 @@ hnae_init_ring(struct hnae_queue *q, struct hnae_ring *ring, int flags)
+ ring->q = q;
+ ring->flags = flags;
+ spin_lock_init(&ring->lock);
++ ring->coal_param = q->handle->coal_param;
+ assert(!ring->desc && !ring->desc_cb && !ring->desc_dma_addr);
+
+ /* not matter for tx or rx ring, the ntc and ntc start from 0 */
+diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
+index 7ba653af19cb..3e62692af011 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
++++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
+@@ -89,6 +89,10 @@ do { \
+
+ #define RCB_RING_NAME_LEN 16
+
++#define HNAE_LOWEST_LATENCY_COAL_PARAM 30
++#define HNAE_LOW_LATENCY_COAL_PARAM 80
++#define HNAE_BULK_LATENCY_COAL_PARAM 150
++
+ enum hnae_led_state {
+ HNAE_LED_INACTIVE,
+ HNAE_LED_ACTIVE,
+@@ -292,6 +296,12 @@ struct hnae_ring {
+
+ int flags; /* ring attribute */
+ int irq_init_flag;
++
++ /* total rx bytes after last rx rate calucated */
++ u64 coal_last_rx_bytes;
++ unsigned long coal_last_jiffies;
++ u32 coal_param;
++ u32 coal_rx_rate; /* rx rate in MB */
+ };
+
+ #define ring_ptr_move_fw(ring, p) \
+@@ -548,8 +558,13 @@ struct hnae_handle {
+ u32 if_support;
+ int q_num;
+ int vf_id;
++ unsigned long coal_last_jiffies;
++ u32 coal_param; /* self adapt coalesce param */
++ /* the ring index of last ring that set coal param */
++ u32 coal_ring_idx;
+ u32 eport_id;
+ u32 dport_id; /* v2 tx bd should fill the dport_id */
++ bool coal_adapt_en;
+ enum hnae_port_type port_type;
+ enum hnae_media_type media_type;
+ struct list_head node; /* list to hnae_ae_dev->handle_list */
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+index a37166ee577b..bd68379d2bea 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+@@ -99,6 +99,7 @@ struct hnae_handle *hns_ae_get_handle(struct hnae_ae_dev *dev,
+ ae_handle->owner_dev = dsaf_dev->dev;
+ ae_handle->dev = dev;
+ ae_handle->q_num = qnum_per_vf;
++ ae_handle->coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
+
+ /* find ring pair, and set vf id*/
+ for (ae_handle->vf_id = 0;
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+index 3987699f8fe6..832f27792e3f 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+@@ -812,6 +812,112 @@ static int hns_desc_unused(struct hnae_ring *ring)
+ return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu;
+ }
+
++#define HNS_LOWEST_LATENCY_RATE 27 /* 27 MB/s */
++#define HNS_LOW_LATENCY_RATE 80 /* 80 MB/s */
++
++#define HNS_COAL_BDNUM 3
++
++static u32 hns_coal_rx_bdnum(struct hnae_ring *ring)
++{
++ bool coal_enable = ring->q->handle->coal_adapt_en;
++
++ if (coal_enable &&
++ ring->coal_last_rx_bytes > HNS_LOWEST_LATENCY_RATE)
++ return HNS_COAL_BDNUM;
++ else
++ return 0;
++}
++
++static void hns_update_rx_rate(struct hnae_ring *ring)
++{
++ bool coal_enable = ring->q->handle->coal_adapt_en;
++ u32 time_passed_ms;
++ u64 total_bytes;
++
++ if (!coal_enable ||
++ time_before(jiffies, ring->coal_last_jiffies + (HZ >> 4)))
++ return;
++
++ /* ring->stats.rx_bytes overflowed */
++ if (ring->coal_last_rx_bytes > ring->stats.rx_bytes) {
++ ring->coal_last_rx_bytes = ring->stats.rx_bytes;
++ ring->coal_last_jiffies = jiffies;
++ return;
++ }
++
++ total_bytes = ring->stats.rx_bytes - ring->coal_last_rx_bytes;
++ time_passed_ms = jiffies_to_msecs(jiffies - ring->coal_last_jiffies);
++ ring->coal_rx_rate = (total_bytes / time_passed_ms) >> 10;
++
++ ring->coal_last_rx_bytes = ring->stats.rx_bytes;
++ ring->coal_last_jiffies = jiffies;
++}
++
++/**
++ * smooth_alg - smoothing algrithm for adjusting coalesce parameter
++ **/
++static u32 smooth_alg(u32 new_param, u32 old_param)
++{
++ u32 gap = (new_param > old_param) ? new_param - old_param
++ : old_param - new_param;
++
++ if (gap > 8)
++ gap >>= 3;
++
++ if (new_param > old_param)
++ return old_param + gap;
++ else
++ return old_param - gap;
++}
++
++/**
++ * hns_nic_adp_coalesce - self adapte coalesce according to rx rate
++ * @ring_data: pointer to hns_nic_ring_data
++ **/
++static void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
++{
++ struct hnae_ring *ring = ring_data->ring;
++ struct hnae_handle *handle = ring->q->handle;
++ u32 new_coal_param, old_coal_param = ring->coal_param;
++
++ if (ring->coal_rx_rate < HNS_LOWEST_LATENCY_RATE)
++ new_coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
++ else if (ring->coal_rx_rate < HNS_LOW_LATENCY_RATE)
++ new_coal_param = HNAE_LOW_LATENCY_COAL_PARAM;
++ else
++ new_coal_param = HNAE_BULK_LATENCY_COAL_PARAM;
++
++ if (new_coal_param == old_coal_param &&
++ new_coal_param == handle->coal_param)
++ return;
++
++ new_coal_param = smooth_alg(new_coal_param, old_coal_param);
++ ring->coal_param = new_coal_param;
++
++ /**
++ * Because all ring in one port has one coalesce param, when one ring
++ * calculate its own coalesce param, it cannot write to hardware at
++ * once. There are three conditions as follows:
++ * 1. current ring's coalesce param is larger than the hardware.
++ * 2. or ring which adapt last time can change again.
++ * 3. timeout.
++ */
++ if (new_coal_param == handle->coal_param) {
++ handle->coal_last_jiffies = jiffies;
++ handle->coal_ring_idx = ring_data->queue_index;
++ } else if (new_coal_param > handle->coal_param ||
++ handle->coal_ring_idx == ring_data->queue_index ||
++ time_after(jiffies, handle->coal_last_jiffies + (HZ >> 4))) {
++ handle->dev->ops->set_coalesce_usecs(handle,
++ new_coal_param);
++ handle->dev->ops->set_coalesce_frames(handle,
++ 1, new_coal_param);
++ handle->coal_param = new_coal_param;
++ handle->coal_ring_idx = ring_data->queue_index;
++ handle->coal_last_jiffies = jiffies;
++ }
++}
++
+ static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data,
+ int budget, void *v)
+ {
+@@ -868,20 +974,27 @@ static bool hns_nic_rx_fini_pro(struct hns_nic_ring_data *ring_data)
+ {
+ struct hnae_ring *ring = ring_data->ring;
+ int num = 0;
++ bool rx_stopped;
+
+- ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
++ hns_update_rx_rate(ring);
+
+ /* for hardware bug fixed */
++ ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
+ num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
+
+- if (num > 0) {
++ if (num <= hns_coal_rx_bdnum(ring)) {
++ if (ring->q->handle->coal_adapt_en)
++ hns_nic_adpt_coalesce(ring_data);
++
++ rx_stopped = true;
++ } else {
+ ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
+ ring_data->ring, 1);
+
+- return false;
+- } else {
+- return true;
++ rx_stopped = false;
+ }
++
++ return rx_stopped;
+ }
+
+ static bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
+@@ -889,12 +1002,17 @@ static bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
+ struct hnae_ring *ring = ring_data->ring;
+ int num;
+
++ hns_update_rx_rate(ring);
+ num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
+
+- if (!num)
++ if (num <= hns_coal_rx_bdnum(ring)) {
++ if (ring->q->handle->coal_adapt_en)
++ hns_nic_adpt_coalesce(ring_data);
++
+ return true;
+- else
+- return false;
++ }
++
++ return false;
+ }
+
+ static inline void hns_nic_reclaim_one_desc(struct hnae_ring *ring,
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.h b/drivers/net/ethernet/hisilicon/hns/hns_enet.h
+index 9cb4c7884201..26e9afcbdd50 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.h
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.h
+@@ -38,7 +38,7 @@ struct hns_nic_ring_data {
+ struct hnae_ring *ring;
+ struct napi_struct napi;
+ cpumask_t mask; /* affinity mask */
+- int queue_index;
++ u32 queue_index;
+ int (*poll_one)(struct hns_nic_ring_data *, int, void *);
+ void (*ex_process)(struct hns_nic_ring_data *, struct sk_buff *);
+ bool (*fini_process)(struct hns_nic_ring_data *);
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+index 78cb20c67aa6..7ea7f8a4aa2a 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+@@ -735,8 +735,8 @@ static int hns_get_coalesce(struct net_device *net_dev,
+
+ ops = priv->ae_handle->dev->ops;
+
+- ec->use_adaptive_rx_coalesce = 1;
+- ec->use_adaptive_tx_coalesce = 1;
++ ec->use_adaptive_rx_coalesce = priv->ae_handle->coal_adapt_en;
++ ec->use_adaptive_tx_coalesce = priv->ae_handle->coal_adapt_en;
+
+ if ((!ops->get_coalesce_usecs) ||
+ (!ops->get_max_coalesced_frames))
+@@ -787,6 +787,9 @@ static int hns_set_coalesce(struct net_device *net_dev,
+ (!ops->set_coalesce_frames))
+ return -ESRCH;
+
++ if (ec->use_adaptive_rx_coalesce != priv->ae_handle->coal_adapt_en)
++ priv->ae_handle->coal_adapt_en = ec->use_adaptive_rx_coalesce;
++
+ rc1 = ops->set_coalesce_usecs(priv->ae_handle,
+ ec->rx_coalesce_usecs);
+
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch b/patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch
new file mode 100644
index 0000000000..87690a3b68
--- /dev/null
+++ b/patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch
@@ -0,0 +1,64 @@
+From: Lin Yun Sheng <linyunsheng@huawei.com>
+Date: Wed, 12 Jul 2017 19:09:59 +0800
+Subject: net: hns: Bugfix for Tx timeout handling in hns driver
+Git-commit: 76b825ab870be3281edac4ae8a414da6e54b0d3a
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+When hns port type is not debug mode, netif_tx_disable is called
+when there is a tx timeout, which requires system reboot to return
+to normal state. This patch fix this problem by resetting the net
+dev.
+
+Fixes: b5996f11ea54 ("net: add Hisilicon Network Subsystem basic ethernet support")
+Signed-off-by: Lin Yun Sheng <linyunsheng@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_enet.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+index fe166e0f6781..3987699f8fe6 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+@@ -1378,13 +1378,20 @@ void hns_nic_net_reset(struct net_device *ndev)
+ void hns_nic_net_reinit(struct net_device *netdev)
+ {
+ struct hns_nic_priv *priv = netdev_priv(netdev);
++ enum hnae_port_type type = priv->ae_handle->port_type;
+
+ netif_trans_update(priv->netdev);
+ while (test_and_set_bit(NIC_STATE_REINITING, &priv->state))
+ usleep_range(1000, 2000);
+
+ hns_nic_net_down(netdev);
+- hns_nic_net_reset(netdev);
++
++ /* Only do hns_nic_net_reset in debug mode
++ * because of hardware limitation.
++ */
++ if (type == HNAE_PORT_DEBUG)
++ hns_nic_net_reset(netdev);
++
+ (void)hns_nic_net_up(netdev);
+ clear_bit(NIC_STATE_REINITING, &priv->state);
+ }
+@@ -1997,13 +2004,8 @@ static void hns_nic_reset_subtask(struct hns_nic_priv *priv)
+ rtnl_lock();
+ /* put off any impending NetWatchDogTimeout */
+ netif_trans_update(priv->netdev);
++ hns_nic_net_reinit(priv->netdev);
+
+- if (type == HNAE_PORT_DEBUG) {
+- hns_nic_net_reinit(priv->netdev);
+- } else {
+- netif_carrier_off(priv->netdev);
+- netif_tx_disable(priv->netdev);
+- }
+ rtnl_unlock();
+ }
+
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch b/patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch
new file mode 100644
index 0000000000..52fad5bb4b
--- /dev/null
+++ b/patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch
@@ -0,0 +1,153 @@
+From: Yunsheng Lin <linyunsheng@huawei.com>
+Date: Thu, 6 Jul 2017 10:22:00 +0800
+Subject: net: hns: Fix a skb used after free bug
+Git-commit: 27463ad99f738ed93c7c8b3e2e5bc8c4853a2ff2
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+skb maybe freed in hns_nic_net_xmit_hw() and return NETDEV_TX_OK,
+which cause hns_nic_net_xmit to use a freed skb.
+
+BUG: KASAN: use-after-free in hns_nic_net_xmit_hw+0x62c/0x940...
+ [17659.112635] alloc_debug_processing+0x18c/0x1a0
+ [17659.117208] __slab_alloc+0x52c/0x560
+ [17659.120909] kmem_cache_alloc_node+0xac/0x2c0
+ [17659.125309] __alloc_skb+0x6c/0x260
+ [17659.128837] tcp_send_ack+0x8c/0x280
+ [17659.132449] __tcp_ack_snd_check+0x9c/0xf0
+ [17659.136587] tcp_rcv_established+0x5a4/0xa70
+ [17659.140899] tcp_v4_do_rcv+0x27c/0x620
+ [17659.144687] tcp_prequeue_process+0x108/0x170
+ [17659.149085] tcp_recvmsg+0x940/0x1020
+ [17659.152787] inet_recvmsg+0x124/0x180
+ [17659.156488] sock_recvmsg+0x64/0x80
+ [17659.160012] SyS_recvfrom+0xd8/0x180
+ [17659.163626] __sys_trace_return+0x0/0x4
+ [17659.167506] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=23 cpu=1 pid=13
+ [17659.174000] free_debug_processing+0x1d4/0x2c0
+ [17659.178486] __slab_free+0x240/0x390
+ [17659.182100] kmem_cache_free+0x24c/0x270
+ [17659.186062] kfree_skbmem+0xa0/0xb0
+ [17659.189587] __kfree_skb+0x28/0x40
+ [17659.193025] napi_gro_receive+0x168/0x1c0
+ [17659.197074] hns_nic_rx_up_pro+0x58/0x90
+ [17659.201038] hns_nic_rx_poll_one+0x518/0xbc0
+ [17659.205352] hns_nic_common_poll+0x94/0x140
+ [17659.209576] net_rx_action+0x458/0x5e0
+ [17659.213363] __do_softirq+0x1b8/0x480
+ [17659.217062] run_ksoftirqd+0x64/0x80
+ [17659.220679] smpboot_thread_fn+0x224/0x310
+ [17659.224821] kthread+0x150/0x170
+ [17659.228084] ret_from_fork+0x10/0x40
+
+ BUG: KASAN: use-after-free in hns_nic_net_xmit+0x8c/0xc0...
+ [17751.080490] __slab_alloc+0x52c/0x560
+ [17751.084188] kmem_cache_alloc+0x244/0x280
+ [17751.088238] __build_skb+0x40/0x150
+ [17751.091764] build_skb+0x28/0x100
+ [17751.095115] __alloc_rx_skb+0x94/0x150
+ [17751.098900] __napi_alloc_skb+0x34/0x90
+ [17751.102776] hns_nic_rx_poll_one+0x180/0xbc0
+ [17751.107097] hns_nic_common_poll+0x94/0x140
+ [17751.111333] net_rx_action+0x458/0x5e0
+ [17751.115123] __do_softirq+0x1b8/0x480
+ [17751.118823] run_ksoftirqd+0x64/0x80
+ [17751.122437] smpboot_thread_fn+0x224/0x310
+ [17751.126575] kthread+0x150/0x170
+ [17751.129838] ret_from_fork+0x10/0x40
+ [17751.133454] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=19 cpu=7 pid=43
+ [17751.139951] free_debug_processing+0x1d4/0x2c0
+ [17751.144436] __slab_free+0x240/0x390
+ [17751.148051] kmem_cache_free+0x24c/0x270
+ [17751.152014] kfree_skbmem+0xa0/0xb0
+ [17751.155543] __kfree_skb+0x28/0x40
+ [17751.159022] napi_gro_receive+0x168/0x1c0
+ [17751.163074] hns_nic_rx_up_pro+0x58/0x90
+ [17751.167041] hns_nic_rx_poll_one+0x518/0xbc0
+ [17751.171358] hns_nic_common_poll+0x94/0x140
+ [17751.175585] net_rx_action+0x458/0x5e0
+ [17751.179373] __do_softirq+0x1b8/0x480
+ [17751.183076] run_ksoftirqd+0x64/0x80
+ [17751.186691] smpboot_thread_fn+0x224/0x310
+ [17751.190826] kthread+0x150/0x170
+ [17751.194093] ret_from_fork+0x10/0x40
+
+Fixes: 13ac695e7ea1 ("net:hns: Add support of Hip06 SoC to the Hislicon Network Subsystem")
+Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
+Signed-off-by: lipeng <lipeng321@huawei.com>
+Reported-by: Jun He <hjat2005@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 ++++++++++------------
+ drivers/net/ethernet/hisilicon/hns/hns_enet.h | 6 +++---
+ 2 files changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+index c6700b91a2df..fe166e0f6781 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+@@ -300,9 +300,9 @@ static void fill_tso_desc(struct hnae_ring *ring, void *priv,
+ mtu);
+ }
+
+-int hns_nic_net_xmit_hw(struct net_device *ndev,
+- struct sk_buff *skb,
+- struct hns_nic_ring_data *ring_data)
++netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
++ struct sk_buff *skb,
++ struct hns_nic_ring_data *ring_data)
+ {
+ struct hns_nic_priv *priv = netdev_priv(ndev);
+ struct hnae_ring *ring = ring_data->ring;
+@@ -361,6 +361,10 @@ int hns_nic_net_xmit_hw(struct net_device *ndev,
+ dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping);
+ netdev_tx_sent_queue(dev_queue, skb->len);
+
++ netif_trans_update(ndev);
++ ndev->stats.tx_bytes += skb->len;
++ ndev->stats.tx_packets++;
++
+ wmb(); /* commit all data before submit */
+ assert(skb->queue_mapping < priv->ae_handle->q_num);
+ hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num);
+@@ -1469,17 +1473,11 @@ static netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+ {
+ struct hns_nic_priv *priv = netdev_priv(ndev);
+- int ret;
+
+ assert(skb->queue_mapping < ndev->ae_handle->q_num);
+- ret = hns_nic_net_xmit_hw(ndev, skb,
+- &tx_ring_data(priv, skb->queue_mapping));
+- if (ret == NETDEV_TX_OK) {
+- netif_trans_update(ndev);
+- ndev->stats.tx_bytes += skb->len;
+- ndev->stats.tx_packets++;
+- }
+- return (netdev_tx_t)ret;
++
++ return hns_nic_net_xmit_hw(ndev, skb,
++ &tx_ring_data(priv, skb->queue_mapping));
+ }
+
+ static void hns_nic_drop_rx_fetch(struct hns_nic_ring_data *ring_data,
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.h b/drivers/net/ethernet/hisilicon/hns/hns_enet.h
+index 1b83232082b2..9cb4c7884201 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.h
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.h
+@@ -92,8 +92,8 @@ void hns_ethtool_set_ops(struct net_device *ndev);
+ void hns_nic_net_reset(struct net_device *ndev);
+ void hns_nic_net_reinit(struct net_device *netdev);
+ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h);
+-int hns_nic_net_xmit_hw(struct net_device *ndev,
+- struct sk_buff *skb,
+- struct hns_nic_ring_data *ring_data);
++netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
++ struct sk_buff *skb,
++ struct hns_nic_ring_data *ring_data);
+
+ #endif /**__HNS_ENET_H */
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch b/patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch
new file mode 100644
index 0000000000..6266d2ca65
--- /dev/null
+++ b/patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch
@@ -0,0 +1,36 @@
+From: Yunsheng Lin <linyunsheng@huawei.com>
+Date: Thu, 6 Jul 2017 10:21:59 +0800
+Subject: net: hns: Fix a wrong op phy C45 code
+Git-commit: ebe8d359c90d6e237527f4d0544b62bdcc0ff286
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+As the user manual described, the second step to write to C45 phy
+by mdio should be data, but not address. Here we should fix this
+issue.
+
+Fixes: 5b904d39406a ("net: add Hisilicon Network Subsystem MDIO support")
+Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
+Reviewed-by: lipeng <lipeng321@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns_mdio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
+index e5221d95afe1..017e08452d8c 100644
+--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
++++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
+@@ -261,7 +261,7 @@ static int hns_mdio_write(struct mii_bus *bus,
+
+ /* config the data needed writing */
+ cmd_reg_cfg = devad;
+- op = MDIO_C45_WRITE_ADDR;
++ op = MDIO_C45_WRITE_DATA;
+ }
+
+ MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch b/patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch
new file mode 100644
index 0000000000..e55d71436d
--- /dev/null
+++ b/patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch
@@ -0,0 +1,35 @@
+From: Lin Yun Sheng <linyunsheng@huawei.com>
+Date: Fri, 4 Aug 2017 17:24:59 +0800
+Subject: net: hns: Fix for __udivdi3 compiler error
+Git-commit: 967b2e2a76e380abdebe7f3c7ab17e8831accd21
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+This patch fixes the __udivdi3 undefined error reported by
+test robot.
+
+Fixes: b8c17f708831 ("net: hns: Add self-adaptive interrupt coalesce support in hns driver")
+Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_enet.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+index 832f27792e3f..36520634c96a 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+@@ -847,7 +847,8 @@ static void hns_update_rx_rate(struct hnae_ring *ring)
+
+ total_bytes = ring->stats.rx_bytes - ring->coal_last_rx_bytes;
+ time_passed_ms = jiffies_to_msecs(jiffies - ring->coal_last_jiffies);
+- ring->coal_rx_rate = (total_bytes / time_passed_ms) >> 10;
++ do_div(total_bytes, time_passed_ms);
++ ring->coal_rx_rate = total_bytes >> 10;
+
+ ring->coal_last_rx_bytes = ring->stats.rx_bytes;
+ ring->coal_last_jiffies = jiffies;
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch b/patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch
new file mode 100644
index 0000000000..819d9c2f3f
--- /dev/null
+++ b/patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch
@@ -0,0 +1,190 @@
+From: Lin Yun Sheng <linyunsheng@huawei.com>
+Date: Fri, 30 Jun 2017 17:44:16 +0800
+Subject: net: hns: Use phy_driver to setup Phy loopback
+Git-commit: 67cd9a997f1bfb5dedf407ad540232912bd04b10
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Use function set_loopback in phy_driver to setup phy loopback
+when doing ethtool self test.
+
+Signed-off-by: Lin Yun Sheng <linyunsheng@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hnae.h | 1 +
+ drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ++++++++---------------
+ 2 files changed, 35 insertions(+), 71 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
+index 04211ac73b36..7ba653af19cb 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
++++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
+@@ -360,6 +360,7 @@ enum hnae_loop {
+ MAC_INTERNALLOOP_MAC = 0,
+ MAC_INTERNALLOOP_SERDES,
+ MAC_INTERNALLOOP_PHY,
++ MAC_LOOP_PHY_NONE,
+ MAC_LOOP_NONE,
+ };
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+index 00e57bbaf122..a8db27e86a11 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+@@ -259,67 +259,27 @@ static const char hns_nic_test_strs[][ETH_GSTRING_LEN] = {
+
+ static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
+ {
+-#define COPPER_CONTROL_REG 0
+-#define PHY_POWER_DOWN BIT(11)
+-#define PHY_LOOP_BACK BIT(14)
+- u16 val = 0;
+-
+- if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
+- return -ENOTSUPP;
++ int err;
+
+ if (en) {
+- /* speed : 1000M */
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
+- phy_write(phy_dev, 21, 0x1046);
+-
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
+- /* Force Master */
+- phy_write(phy_dev, 9, 0x1F00);
+-
+- /* Soft-reset */
+- phy_write(phy_dev, 0, 0x9140);
+- /* If autoneg disabled,two soft-reset operations */
+- phy_write(phy_dev, 0, 0x9140);
+-
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
+-
+- /* Default is 0x0400 */
+- phy_write(phy_dev, 1, 0x418);
+-
+- /* Force 1000M Link, Default is 0x0200 */
+- phy_write(phy_dev, 7, 0x20C);
+-
+- /* Powerup Fiber */
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
+- val = phy_read(phy_dev, COPPER_CONTROL_REG);
+- val &= ~PHY_POWER_DOWN;
+- phy_write(phy_dev, COPPER_CONTROL_REG, val);
+-
+- /* Enable Phy Loopback */
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
+- val = phy_read(phy_dev, COPPER_CONTROL_REG);
+- val |= PHY_LOOP_BACK;
+- val &= ~PHY_POWER_DOWN;
+- phy_write(phy_dev, COPPER_CONTROL_REG, val);
++ /* Doing phy loopback in offline state, phy resuming is
++ * needed to power up the device.
++ */
++ err = phy_resume(phy_dev);
++ if (err)
++ goto out;
++
++ err = phy_loopback(phy_dev, true);
+ } else {
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
+- phy_write(phy_dev, 1, 0x400);
+- phy_write(phy_dev, 7, 0x200);
+-
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
+- val = phy_read(phy_dev, COPPER_CONTROL_REG);
+- val |= PHY_POWER_DOWN;
+- phy_write(phy_dev, COPPER_CONTROL_REG, val);
+-
+- phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
+- phy_write(phy_dev, 9, 0xF00);
+-
+- val = phy_read(phy_dev, COPPER_CONTROL_REG);
+- val &= ~PHY_LOOP_BACK;
+- val |= PHY_POWER_DOWN;
+- phy_write(phy_dev, COPPER_CONTROL_REG, val);
++ err = phy_loopback(phy_dev, false);
++ if (err)
++ goto out;
++
++ err = phy_suspend(phy_dev);
+ }
+- return 0;
++
++out:
++ return err;
+ }
+
+ static int __lb_setup(struct net_device *ndev,
+@@ -332,10 +292,9 @@ static int __lb_setup(struct net_device *ndev,
+
+ switch (loop) {
+ case MAC_INTERNALLOOP_PHY:
+- if ((phy_dev) && (!phy_dev->is_c45)) {
+- ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+- ret |= h->dev->ops->set_loopback(h, loop, 0x1);
+- }
++ ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
++ if (!ret)
++ ret = h->dev->ops->set_loopback(h, loop, 0x1);
+ break;
+ case MAC_INTERNALLOOP_MAC:
+ if ((h->dev->ops->set_loopback) &&
+@@ -346,17 +305,17 @@ static int __lb_setup(struct net_device *ndev,
+ if (h->dev->ops->set_loopback)
+ ret = h->dev->ops->set_loopback(h, loop, 0x1);
+ break;
++ case MAC_LOOP_PHY_NONE:
++ ret = hns_nic_config_phy_loopback(phy_dev, 0x0);
+ case MAC_LOOP_NONE:
+- if ((phy_dev) && (!phy_dev->is_c45))
+- ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
+-
+- if (h->dev->ops->set_loopback) {
++ if (!ret && h->dev->ops->set_loopback) {
+ if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
+- ret |= h->dev->ops->set_loopback(h,
++ ret = h->dev->ops->set_loopback(h,
+ MAC_INTERNALLOOP_MAC, 0x0);
+
+- ret |= h->dev->ops->set_loopback(h,
+- MAC_INTERNALLOOP_SERDES, 0x0);
++ if (!ret)
++ ret = h->dev->ops->set_loopback(h,
++ MAC_INTERNALLOOP_SERDES, 0x0);
+ }
+ break;
+ default:
+@@ -582,13 +541,16 @@ static int __lb_run_test(struct net_device *ndev,
+ return ret_val;
+ }
+
+-static int __lb_down(struct net_device *ndev)
++static int __lb_down(struct net_device *ndev, enum hnae_loop loop)
+ {
+ struct hns_nic_priv *priv = netdev_priv(ndev);
+ struct hnae_handle *h = priv->ae_handle;
+ int ret;
+
+- ret = __lb_setup(ndev, MAC_LOOP_NONE);
++ if (loop == MAC_INTERNALLOOP_PHY)
++ ret = __lb_setup(ndev, MAC_LOOP_PHY_NONE);
++ else
++ ret = __lb_setup(ndev, MAC_LOOP_NONE);
+ if (ret)
+ netdev_err(ndev, "%s: __lb_setup return error(%d)!\n",
+ __func__,
+@@ -644,7 +606,8 @@ static void hns_nic_self_test(struct net_device *ndev,
+ if (!data[test_index]) {
+ data[test_index] = __lb_run_test(
+ ndev, (enum hnae_loop)st_param[i][0]);
+- (void)__lb_down(ndev);
++ (void)__lb_down(ndev,
++ (enum hnae_loop)st_param[i][0]);
+ }
+
+ if (data[test_index])
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch b/patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch
new file mode 100644
index 0000000000..0bd44465f3
--- /dev/null
+++ b/patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch
@@ -0,0 +1,130 @@
+From: LiuJian <liujian56@huawei.com>
+Date: Thu, 13 Jul 2017 18:57:54 +0800
+Subject: net: hns: add acpi function of xge led control
+Git-commit: 1e4babee70a2e2d8f9e0da06f013563b0e26f654
+Patch-mainline: v4.13-rc2
+References: bsc#1068693
+
+The current code only support DT method to control xge led.
+This patch is the implementation of acpi method to control xge led.
+
+Signed-off-by: LiuJian <liujian56@huawei.com>
+Reviewed-by: John Garry <john.garry@huawei.com>
+Reviewed-by: Yunsheng Lin <linyunsheng@huawei.com>
+Reviewed-by: Daode Huang <huangdaode@hisilicon.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[mb: change hns_dsaf_acpi_dsm_guid to hns_dsaf_acpi_dsm_uuid]
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 3 +-
+ drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 58 +++++++++++++++++++++-
+ 2 files changed, 58 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+index ff864a187d5a..a37166ee577b 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+@@ -776,8 +776,9 @@ void hns_ae_update_led_status(struct hnae_handle *handle)
+
+ assert(handle);
+ mac_cb = hns_get_mac_cb(handle);
+- if (!mac_cb->cpld_ctrl)
++ if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
+ return;
++
+ hns_set_led_opt(mac_cb);
+ }
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+index 7a8addda726e..408b63faf9a8 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+@@ -53,6 +53,34 @@ static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg)
+ return ret;
+ }
+
++static void hns_dsaf_acpi_ledctrl_by_port(struct hns_mac_cb *mac_cb, u8 op_type,
++ u32 link, u32 port, u32 act)
++{
++ union acpi_object *obj;
++ union acpi_object obj_args[3], argv4;
++
++ obj_args[0].integer.type = ACPI_TYPE_INTEGER;
++ obj_args[0].integer.value = link;
++ obj_args[1].integer.type = ACPI_TYPE_INTEGER;
++ obj_args[1].integer.value = port;
++ obj_args[2].integer.type = ACPI_TYPE_INTEGER;
++ obj_args[2].integer.value = act;
++
++ argv4.type = ACPI_TYPE_PACKAGE;
++ argv4.package.count = 3;
++ argv4.package.elements = obj_args;
++
++ obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
++ hns_dsaf_acpi_dsm_uuid, 0, op_type, &argv4);
++ if (!obj) {
++ dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
++ link, port, act);
++ return;
++ }
++
++ ACPI_FREE(obj);
++}
++
+ static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
+ u16 speed, int data)
+ {
+@@ -93,6 +121,18 @@ static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
+ }
+ }
+
++static void hns_cpld_set_led_acpi(struct hns_mac_cb *mac_cb, int link_status,
++ u16 speed, int data)
++{
++ if (!mac_cb) {
++ pr_err("cpld_led_set mac_cb is null!\n");
++ return;
++ }
++
++ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
++ link_status, mac_cb->mac_id, data);
++}
++
+ static void cpld_led_reset(struct hns_mac_cb *mac_cb)
+ {
+ if (!mac_cb || !mac_cb->cpld_ctrl)
+@@ -103,6 +143,20 @@ static void cpld_led_reset(struct hns_mac_cb *mac_cb)
+ mac_cb->cpld_led_value = CPLD_LED_DEFAULT_VALUE;
+ }
+
++static void cpld_led_reset_acpi(struct hns_mac_cb *mac_cb)
++{
++ if (!mac_cb) {
++ pr_err("cpld_led_reset mac_cb is null!\n");
++ return;
++ }
++
++ if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
++ return;
++
++ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
++ 0, mac_cb->mac_id, 0);
++}
++
+ static int cpld_set_led_id(struct hns_mac_cb *mac_cb,
+ enum hnae_led_state status)
+ {
+@@ -604,8 +658,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
+
+ misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback;
+ } else if (is_acpi_node(dsaf_dev->dev->fwnode)) {
+- misc_op->cpld_set_led = hns_cpld_set_led;
+- misc_op->cpld_reset_led = cpld_led_reset;
++ misc_op->cpld_set_led = hns_cpld_set_led_acpi;
++ misc_op->cpld_reset_led = cpld_led_reset_acpi;
+ misc_op->cpld_set_led_id = cpld_set_led_id;
+
+ misc_op->dsaf_reset = hns_dsaf_rst_acpi;
+--
+2.14.2
+
diff --git a/patches.drivers/net-hns-set-correct-return-value.patch b/patches.drivers/net-hns-set-correct-return-value.patch
new file mode 100644
index 0000000000..85a16af0af
--- /dev/null
+++ b/patches.drivers/net-hns-set-correct-return-value.patch
@@ -0,0 +1,39 @@
+From: Pan Bian <bianpan2016@163.com>
+Date: Mon, 30 Oct 2017 16:50:01 +0800
+Subject: net: hns: set correct return value
+Git-commit: d2083d0e92117598dd24ba270af12376f1fb8866
+Patch-mainline: v4.14-rc8
+References: bsc#1068693
+
+The function of_parse_phandle() returns a NULL pointer if it cannot
+resolve a phandle property to a device_node pointer. In function
+hns_nic_dev_probe(), its return value is passed to PTR_ERR to extract
+the error code. However, in this case, the extracted error code will
+always be zero, which is unexpected.
+
+Signed-off-by: Pan Bian <bianpan2016@163.com>
+Reviewed-by: Tobias Klauser <tklauser@distanz.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_enet.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+index 36520634c96a..e77192683dba 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+@@ -2369,8 +2369,8 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
+ priv->enet_ver = AE_VERSION_2;
+
+ ae_node = of_parse_phandle(dev->of_node, "ae-handle", 0);
+- if (IS_ERR_OR_NULL(ae_node)) {
+- ret = PTR_ERR(ae_node);
++ if (!ae_node) {
++ ret = -ENODEV;
+ dev_err(dev, "not find ae-handle\n");
+ goto out_read_prop_fail;
+ }
+--
+2.14.2
+
diff --git a/patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch b/patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch
new file mode 100644
index 0000000000..3e7614671c
--- /dev/null
+++ b/patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch
@@ -0,0 +1,149 @@
+From: Lin Yun Sheng <linyunsheng@huawei.com>
+Date: Fri, 30 Jun 2017 17:44:15 +0800
+Subject: net: phy: Add phy loopback support in net phy framework
+Git-commit: f0f9b4ed23381d97cde2ac64248198bc43608e6d
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+This patch add set_loopback in phy_driver, which is used by MAC
+driver to enable or disable phy loopback. it also add a generic
+genphy_loopback function, which use BMCR loopback bit to enable
+or disable loopback.
+
+Signed-off-by: Lin Yun Sheng <linyunsheng@huawei.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/net/phy/marvell.c | 1
+ drivers/net/phy/phy_device.c | 51 +++++++++++++++++++++++++++++++++++++++++++
+ include/linux/phy.h | 5 ++++
+ 3 files changed, 57 insertions(+)
+
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -2094,6 +2094,7 @@ static struct phy_driver marvell_drivers
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
++ .set_loopback = genphy_loopback,
+ },
+ {
+ .phy_id = MARVELL_PHY_ID_88E1540,
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1123,6 +1123,39 @@ int phy_resume(struct phy_device *phydev
+ }
+ EXPORT_SYMBOL(phy_resume);
+
++int phy_loopback(struct phy_device *phydev, bool enable)
++{
++ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
++ int ret = 0;
++
++ mutex_lock(&phydev->lock);
++
++ if (enable && phydev->loopback_enabled) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ if (!enable && !phydev->loopback_enabled) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (phydev->drv && phydrv->set_loopback)
++ ret = phydrv->set_loopback(phydev, enable);
++ else
++ ret = -EOPNOTSUPP;
++
++ if (ret)
++ goto out;
++
++ phydev->loopback_enabled = enable;
++
++out:
++ mutex_unlock(&phydev->lock);
++ return ret;
++}
++EXPORT_SYMBOL(phy_loopback);
++
+ /* Generic PHY support and helper functions */
+
+ /**
+@@ -1628,6 +1661,23 @@ static int gen10g_resume(struct phy_devi
+ return 0;
+ }
+
++int genphy_loopback(struct phy_device *phydev, bool enable)
++{
++ int value;
++
++ value = phy_read(phydev, MII_BMCR);
++ if (value < 0)
++ return value;
++
++ if (enable)
++ value |= BMCR_LOOPBACK;
++ else
++ value &= ~BMCR_LOOPBACK;
++
++ return phy_write(phydev, MII_BMCR, value);
++}
++EXPORT_SYMBOL(genphy_loopback);
++
+ static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
+ {
+ /* The default values for phydev->supported are provided by the PHY
+@@ -1874,6 +1924,7 @@ static struct phy_driver genphy_driver[]
+ .read_status = genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .set_loopback = genphy_loopback,
+ }, {
+ .phy_id = 0xffffffff,
+ .phy_id_mask = 0xffffffff,
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
+ * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
+ * has_fixups: Set to true if this phy has fixups/quirks.
+ * suspended: Set to true if this phy has been suspended successfully.
++ * loopback_enabled: Set true if this phy has been loopbacked successfully.
+ * state: state of the PHY for management purposes
+ * dev_flags: Device-specific flags used by the PHY driver.
+ * link_timeout: The number of timer firings to wait before the
+@@ -400,6 +401,7 @@ struct phy_device {
+ bool is_pseudo_fixed_link;
+ bool has_fixups;
+ bool suspended;
++ bool loopback_enabled;
+
+ enum phy_state state;
+
+@@ -639,6 +641,7 @@ struct phy_driver {
+ int (*set_tunable)(struct phy_device *dev,
+ struct ethtool_tunable *tuna,
+ const void *data);
++ int (*set_loopback)(struct phy_device *dev, bool enable);
+ };
+ #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
+ struct phy_driver, mdiodrv)
+@@ -784,6 +787,7 @@ void phy_device_remove(struct phy_device
+ int phy_init_hw(struct phy_device *phydev);
+ int phy_suspend(struct phy_device *phydev);
+ int phy_resume(struct phy_device *phydev);
++int phy_loopback(struct phy_device *phydev, bool enable);
+ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
+ phy_interface_t interface);
+ struct phy_device *phy_find_first(struct mii_bus *bus);
+@@ -835,6 +839,7 @@ int genphy_update_link(struct phy_device
+ int genphy_read_status(struct phy_device *phydev);
+ int genphy_suspend(struct phy_device *phydev);
+ int genphy_resume(struct phy_device *phydev);
++int genphy_loopback(struct phy_device *phydev, bool enable);
+ int genphy_soft_reset(struct phy_device *phydev);
+ static inline int genphy_no_soft_reset(struct phy_device *phydev)
+ {
diff --git a/patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch b/patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch
new file mode 100644
index 0000000000..7fd336777a
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch
@@ -0,0 +1,183 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:32 +0800
+Subject: scsi: hisi_sas: add irq and tasklet cleanup in v2 hw
+Git-commit: 8a253888bfc395a7a169f20d710d9289e59a8592
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+This patch adds support to clean-up allocated IRQs and kill tasklets
+when probe fails and for driver removal.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 96 +++++++++++++++++-----------------
+ 1 file changed, 49 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index bcbc16e4cec0..9eea0b4e0434 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -3290,97 +3290,92 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
+ {
+ struct platform_device *pdev = hisi_hba->platform_dev;
+ struct device *dev = &pdev->dev;
+- int i, irq, rc, irq_map[128];
+-
++ int irq, rc, irq_map[128];
++ int i, phy_no, fatal_no, queue_no, k;
+
+ for (i = 0; i < 128; i++)
+ irq_map[i] = platform_get_irq(pdev, i);
+
+ for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
+- int idx = i;
+-
+- irq = irq_map[idx + 1]; /* Phy up/down is irq1 */
+- if (!irq) {
+- dev_err(dev, "irq init: fail map phy interrupt %d\n",
+- idx);
+- return -ENOENT;
+- }
+-
++ irq = irq_map[i + 1]; /* Phy up/down is irq1 */
+ rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
+ DRV_NAME " phy", hisi_hba);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+- return -ENOENT;
++ rc = -ENOENT;
++ goto free_phy_int_irqs;
+ }
+ }
+
+- for (i = 0; i < hisi_hba->n_phy; i++) {
+- struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+- int idx = i + 72; /* First SATA interrupt is irq72 */
+-
+- irq = irq_map[idx];
+- if (!irq) {
+- dev_err(dev, "irq init: fail map phy interrupt %d\n",
+- idx);
+- return -ENOENT;
+- }
++ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
++ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
++ irq = irq_map[phy_no + 72];
+ rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
+ DRV_NAME " sata", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "sata interrupt %d, rc=%d\n",
+ irq, rc);
+- return -ENOENT;
++ rc = -ENOENT;
++ goto free_sata_int_irqs;
+ }
+ }
+
+- for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++) {
+- int idx = i;
+-
+- irq = irq_map[idx + 81];
+- if (!irq) {
+- dev_err(dev, "irq init: fail map fatal interrupt %d\n",
+- idx);
+- return -ENOENT;
+- }
+-
+- rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
++ for (fatal_no = 0; fatal_no < HISI_SAS_FATAL_INT_NR; fatal_no++) {
++ irq = irq_map[fatal_no + 81];
++ rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
+ DRV_NAME " fatal", hisi_hba);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request fatal interrupt %d, rc=%d\n",
+ irq, rc);
+- return -ENOENT;
++ rc = -ENOENT;
++ goto free_fatal_int_irqs;
+ }
+ }
+
+- for (i = 0; i < hisi_hba->queue_count; i++) {
+- int idx = i + 96; /* First cq interrupt is irq96 */
+- struct hisi_sas_cq *cq = &hisi_hba->cq[i];
++ for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
+ struct tasklet_struct *t = &cq->tasklet;
+
+- irq = irq_map[idx];
+- if (!irq) {
+- dev_err(dev,
+- "irq init: could not map cq interrupt %d\n",
+- idx);
+- return -ENOENT;
+- }
++ irq = irq_map[queue_no + 96];
+ rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
+- DRV_NAME " cq", &hisi_hba->cq[i]);
++ DRV_NAME " cq", cq);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+- return -ENOENT;
++ rc = -ENOENT;
++ goto free_cq_int_irqs;
+ }
+ tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
+ }
+
+ return 0;
++
++free_cq_int_irqs:
++ for (k = 0; k < queue_no; k++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[k];
++
++ free_irq(irq_map[k + 96], cq);
++ tasklet_kill(&cq->tasklet);
++ }
++free_fatal_int_irqs:
++ for (k = 0; k < fatal_no; k++)
++ free_irq(irq_map[k + 81], hisi_hba);
++free_sata_int_irqs:
++ for (k = 0; k < phy_no; k++) {
++ struct hisi_sas_phy *phy = &hisi_hba->phy[k];
++
++ free_irq(irq_map[k + 72], phy);
++ }
++free_phy_int_irqs:
++ for (k = 0; k < i; k++)
++ free_irq(irq_map[k + 1], hisi_hba);
++ return rc;
+ }
+
+ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
+@@ -3518,10 +3513,17 @@ static int hisi_sas_v2_remove(struct platform_device *pdev)
+ {
+ struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+ struct hisi_hba *hisi_hba = sha->lldd_ha;
++ int i;
+
+ if (timer_pending(&hisi_hba->timer))
+ del_timer(&hisi_hba->timer);
+
++ for (i = 0; i < hisi_hba->queue_count; i++) {
++ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
++
++ tasklet_kill(&cq->tasklet);
++ }
++
+ return hisi_sas_remove(pdev);
+ }
+
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch b/patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch
new file mode 100644
index 0000000000..335c8c7648
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch
@@ -0,0 +1,35 @@
+From: "Gustavo A. R. Silva" <garsilva@embeddedor.com>
+Date: Mon, 22 May 2017 13:00:29 -0500
+Subject: scsi: hisi_sas: add null check before indirect pointer dereference
+Git-commit: eb045e046d5b2aab7710f82c2e5fb1403c69332b
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Add null check before indirectly dereferencing pointer task->lldd_task
+in statement u32 tag = slot->idx;
+
+Addresses-Coverity-ID: 1373843
+Signed-off-by: Gustavo A. R. Silva <garsilva@embeddedor.com>
+Reviewed-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index d622db502ec9..f720d3ced851 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -963,7 +963,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
+ HISI_SAS_INT_ABT_DEV, 0);
+ rc = hisi_sas_softreset_ata_disk(device);
+ }
+- } else if (task->task_proto & SAS_PROTOCOL_SMP) {
++ } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
+ /* SMP */
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch b/patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch
new file mode 100644
index 0000000000..d07294b7a0
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch
@@ -0,0 +1,543 @@
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 14 Jun 2017 23:33:17 +0800
+Subject: scsi: hisi_sas: add pci_dev in hisi_hba struct
+Git-commit: 11b752490a051b79de183fee73706e13d80d3998
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Since hip08 SAS controller is based on pci device, add hisi_hba.pci_dev
+for hip08 (will be v3), and also rename hisi_hba.pdev to .platform_dev
+for clarity.
+
+In addition, for common code which wants to reference the controller
+device struct, add hisi_hba.dev, and change the common code to use it.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 6 ++++-
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 36 ++++++++++++++--------------
+ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 28 +++++++++++-----------
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 44 +++++++++++++++++-----------------
+ 4 files changed, 59 insertions(+), 55 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 19c6ffd6d4ff..84cac98b368a 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -18,6 +18,7 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
++#include <linux/pci.h>
+ #include <linux/platform_device.h>
+ #include <linux/property.h>
+ #include <linux/regmap.h>
+@@ -196,7 +197,10 @@ struct hisi_hba {
+ /* This must be the first element, used by SHOST_TO_SAS_HA */
+ struct sas_ha_struct *p;
+
+- struct platform_device *pdev;
++ struct platform_device *platform_dev;
++ struct pci_dev *pci_dev;
++ struct device *dev;
++
+ void __iomem *regs;
+ struct regmap *ctrl;
+ u32 ctrl_reset_reg;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index f53a93b1f955..139df4509a41 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -168,7 +168,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+ {
+
+ if (task) {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+
+@@ -245,7 +245,7 @@ static void hisi_sas_slot_abort(struct work_struct *work)
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_tmf_task tmf_task;
+ struct scsi_lun lun;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int tag = abort_slot->idx;
+ unsigned long flags;
+
+@@ -279,7 +279,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
+ struct asd_sas_port *sas_port = device->port;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+ unsigned long flags;
+
+@@ -451,7 +451,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ u32 pass = 0;
+ unsigned long flags;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_dq *dq = sas_dev->dq;
+@@ -546,7 +546,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ if (hisi_hba->hw->alloc_dev)
+ sas_dev = hisi_hba->hw->alloc_dev(device);
+@@ -731,7 +731,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
+ {
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int dev_id = sas_dev->device_id;
+
+ dev_info(dev, "found dev[%d:%x] is gone\n",
+@@ -814,7 +814,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
+ {
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct sas_task *task;
+ int res, retry;
+
+@@ -931,7 +931,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
+ struct ata_link *link;
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int s = sizeof(struct host_to_dev_fis);
+ unsigned long flags;
+
+@@ -989,7 +989,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
+ return -1;
+
+ if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+ unsigned long flags;
+
+@@ -1022,7 +1022,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int rc = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+@@ -1151,7 +1151,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+ {
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+@@ -1240,7 +1240,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ {
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot;
+ struct asd_sas_port *sas_port = device->port;
+@@ -1337,7 +1337,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ {
+ struct sas_task *task;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int res;
+
+ if (!hisi_hba->hw->prep_abort)
+@@ -1547,8 +1547,7 @@ EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
+
+ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+ {
+- struct platform_device *pdev = hisi_hba->pdev;
+- struct device *dev = &pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+
+ spin_lock_init(&hisi_hba->lock);
+@@ -1668,7 +1667,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+
+ static void hisi_sas_free(struct hisi_hba *hisi_hba)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+@@ -1749,7 +1748,8 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+
+ INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
+ hisi_hba->hw = hw;
+- hisi_hba->pdev = pdev;
++ hisi_hba->platform_dev = pdev;
++ hisi_hba->dev = dev;
+ hisi_hba->shost = shost;
+ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+@@ -1866,7 +1866,7 @@ int hisi_sas_probe(struct platform_device *pdev,
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
+
+ sha->sas_ha_name = DRV_NAME;
+- sha->dev = &hisi_hba->pdev->dev;
++ sha->dev = hisi_hba->dev;
+ sha->lldd_module = THIS_MODULE;
+ sha->sas_addr = &hisi_hba->sas_addr[0];
+ sha->num_phys = hisi_hba->n_phy;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+index 7d7d2a7e690d..afa87d4c367a 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+@@ -505,7 +505,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+ {
+ struct domain_device *device = sas_dev->sas_device;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+ struct asd_sas_port *sas_port = device->port;
+@@ -571,7 +571,7 @@ static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
+ int i;
+ unsigned long end_time;
+ u32 val;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_ctrl = hisi_sas_phy_read32(hisi_hba, i, PHY_CTRL);
+@@ -756,7 +756,7 @@ static void init_reg_v1_hw(struct hisi_hba *hisi_hba)
+
+ static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int rc;
+
+ rc = reset_hw_v1_hw(hisi_hba);
+@@ -907,7 +907,7 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+ static int
+ get_free_slot_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int queue = dq->id;
+ u32 r, w;
+
+@@ -939,7 +939,7 @@ static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ struct scatterlist *scatter,
+ int n_elem)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct scatterlist *sg;
+ int i;
+
+@@ -976,7 +976,7 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+@@ -1148,7 +1148,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+ {
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record_v1 *err_record = slot->status_buffer;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+@@ -1274,7 +1274,7 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ {
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+@@ -1423,7 +1423,7 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
+ {
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int i, phy_no = sas_phy->id;
+ u32 irq_value, context, port_id, link_rate;
+@@ -1504,7 +1504,7 @@ static irqreturn_t int_bcast_v1_hw(int irq, void *p)
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int phy_no = sas_phy->id;
+ u32 irq_value;
+ irqreturn_t res = IRQ_HANDLED;
+@@ -1531,7 +1531,7 @@ static irqreturn_t int_abnormal_v1_hw(int irq, void *p)
+ {
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ u32 irq_value, irq_mask_old;
+ int phy_no = sas_phy->id;
+@@ -1634,7 +1634,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
+ static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+ {
+ struct hisi_hba *hisi_hba = p;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 ecc_int = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECC1B_MSK) {
+@@ -1693,7 +1693,7 @@ static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+ static irqreturn_t fatal_axi_int_v1_hw(int irq, void *p)
+ {
+ struct hisi_hba *hisi_hba = p;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 axi_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC2);
+ u32 axi_info = hisi_sas_read32(hisi_hba, HGC_AXI_FIFO_ERR_INFO);
+
+@@ -1731,7 +1731,7 @@ static irq_handler_t fatal_interrupts[HISI_SAS_MAX_QUEUES] = {
+
+ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
+ {
+- struct platform_device *pdev = hisi_hba->pdev;
++ struct platform_device *pdev = hisi_hba->platform_dev;
+ struct device *dev = &pdev->dev;
+ int i, j, irq, rc, idx;
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 9cc54357eeb0..341a0bf6c667 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -653,7 +653,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
+ static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
+ {
+ unsigned int index;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ void *bitmap = hisi_hba->sata_dev_bitmap;
+
+ index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW);
+@@ -754,7 +754,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+ {
+ struct domain_device *device = sas_dev->sas_device;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+ struct domain_device *parent_dev = device->parent;
+@@ -807,7 +807,7 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+ {
+ u64 dev_id = sas_dev->device_id;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ int i;
+@@ -851,7 +851,7 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
+ int i, reset_val;
+ u32 val;
+ unsigned long end_time;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ /* The mask needs to be set depending on the number of phys */
+ if (hisi_hba->n_phy == 9)
+@@ -987,7 +987,7 @@ static void phys_try_accept_stp_links_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 *dev = hisi_hba->dev;
+ int i;
+
+ /* Global registers init */
+@@ -1168,7 +1168,7 @@ static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
+
+ static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int rc;
+
+ rc = reset_hw_v2_hw(hisi_hba);
+@@ -1217,7 +1217,7 @@ static bool tx_fifo_is_empty_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ static bool axi_bus_is_idle_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ {
+ int i, max_loop = 1000;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 status, axi_status, dfx_val, dfx_tx_val;
+
+ for (i = 0; i < max_loop; i++) {
+@@ -1243,7 +1243,7 @@ static bool axi_bus_is_idle_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ static bool wait_io_done_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ {
+ int i, max_loop = 1000;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 status, tx_dfx0;
+
+ for (i = 0; i < max_loop; i++) {
+@@ -1281,7 +1281,7 @@ static bool allowed_disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ {
+ u32 cfg, axi_val, dfx0_val, txid_auto;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ /* Close axi bus. */
+ axi_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
+@@ -1459,7 +1459,7 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
+ static int
+ get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ int queue = dq->id;
+ u32 r, w;
+
+@@ -1492,7 +1492,7 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ struct scatterlist *scatter,
+ int n_elem)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct scatterlist *sg;
+ int i;
+
+@@ -1529,7 +1529,7 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+@@ -2188,7 +2188,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ {
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+@@ -2486,7 +2486,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+ u32 port_id, link_rate, hard_phy_linkrate;
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+
+@@ -2673,7 +2673,7 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
+ {
+ struct hisi_hba *hisi_hba = p;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 ent_msk, ent_tmp, irq_msk;
+ int phy_no = 0;
+
+@@ -2733,7 +2733,7 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
+ static void
+ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 reg_val;
+
+ if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF)) {
+@@ -2822,7 +2822,7 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
+ u32 irq_value)
+ {
+ u32 reg_val;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF)) {
+ reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
+@@ -2972,7 +2972,7 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
+ {
+ struct hisi_hba *hisi_hba = p;
+ u32 irq_value, irq_msk, err_value;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+
+ irq_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk | 0xfffffffe);
+@@ -3148,7 +3148,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ struct hisi_sas_initial_fis *initial_fis;
+ struct dev_to_host_fis *fis;
+ u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
+@@ -3250,7 +3250,7 @@ static irq_handler_t fatal_interrupts[HISI_SAS_FATAL_INT_NR] = {
+ */
+ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
+ {
+- struct platform_device *pdev = hisi_hba->pdev;
++ struct platform_device *pdev = hisi_hba->platform_dev;
+ struct device *dev = &pdev->dev;
+ int i, irq, rc, irq_map[128];
+
+@@ -3364,7 +3364,7 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
+
+ static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
+ {
+- struct platform_device *pdev = hisi_hba->pdev;
++ struct platform_device *pdev = hisi_hba->platform_dev;
+ int i;
+
+ for (i = 0; i < hisi_hba->queue_count; i++)
+@@ -3386,7 +3386,7 @@ static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
+
+ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
+ {
+- struct device *dev = &hisi_hba->pdev->dev;
++ struct device *dev = hisi_hba->dev;
+ u32 old_state, state;
+ int rc, cnt;
+ int phy_no;
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch b/patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch
new file mode 100644
index 0000000000..cab871dc05
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch
@@ -0,0 +1,58 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:35 +0800
+Subject: scsi: hisi_sas: add status and command buffer for internal abort
+Git-commit: 031da09c110106be9697356436ddb915eed8ed26
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+For v3 hw, internal abort function required status and command buffer to
+be set, so add necessary code for this.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 86868ec66178..7e642c8097c7 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -1363,12 +1363,21 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ slot->port = port;
+ task->lldd_task = slot;
+
++ slot->buf = dma_pool_alloc(hisi_hba->buffer_pool,
++ GFP_ATOMIC, &slot->buf_dma);
++ if (!slot->buf) {
++ rc = -ENOMEM;
++ goto err_out_tag;
++ }
++
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
++ memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
++ memset(hisi_sas_status_buf_addr_mem(slot), 0, HISI_SAS_STATUS_BUF_SZ);
+
+ rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
+ abort_flag, task_tag);
+ if (rc)
+- goto err_out_tag;
++ goto err_out_buf;
+
+
+ list_add_tail(&slot->entry, &sas_dev->list);
+@@ -1386,6 +1395,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+
+ return 0;
+
++err_out_buf:
++ dma_pool_free(hisi_hba->buffer_pool, slot->buf,
++ slot->buf_dma);
+ err_out_tag:
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch b/patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch
new file mode 100644
index 0000000000..144bb90956
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch
@@ -0,0 +1,104 @@
+From: Xiaofei Tan <tanxiaofei@huawei.com>
+Date: Fri, 11 Aug 2017 00:09:29 +0800
+Subject: scsi: hisi_sas: add v2 hw DFX feature
+Git-commit: c52108c61bd3e97495858e6c7423d312093fcfba
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+Add DFX feature for v2 hw. We are adding support for
+the following errors:
+- loss_of_dword_sync_count
+- invalid_dword_count
+- phy_reset_problem_count
+- running_disparity_error_count
+
+Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 1 +
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 7 ++++++-
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 22 ++++++++++++++++++++++
+ 3 files changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 3c4defad8c18..ef2238c6e4da 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -193,6 +193,7 @@ struct hisi_sas_hw {
+ void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no);
++ void (*get_events)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no,
+ struct sas_phy_linkrates *linkrates);
+ enum sas_linkrate (*phy_get_max_linkrate)(void);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index bd1d61958e10..aaa7296421a2 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -764,7 +764,12 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+ case PHY_FUNC_SET_LINK_RATE:
+ hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, funcdata);
+ break;
+-
++ case PHY_FUNC_GET_EVENTS:
++ if (hisi_hba->hw->get_events) {
++ hisi_hba->hw->get_events(hisi_hba, phy_no);
++ break;
++ }
++ /* fallthru */
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ default:
+ return -EOPNOTSUPP;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index a762b259f68f..41e8033ad1c8 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -256,6 +256,8 @@
+ #define LINK_DFX2_RCVR_HOLD_STS_MSK (0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF)
+ #define LINK_DFX2_SEND_HOLD_STS_OFF 10
+ #define LINK_DFX2_SEND_HOLD_STS_MSK (0x1 << LINK_DFX2_SEND_HOLD_STS_OFF)
++#define SAS_ERR_CNT4_REG (PORT_BASE + 0x290)
++#define SAS_ERR_CNT6_REG (PORT_BASE + 0x298)
+ #define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
+ #define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
+ #define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
+@@ -1360,6 +1362,25 @@ static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+ start_phy_v2_hw(hisi_hba, phy_no);
+ }
+
++static void phy_get_events_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
++{
++ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
++ struct asd_sas_phy *sas_phy = &phy->sas_phy;
++ struct sas_phy *sphy = sas_phy->phy;
++ u32 err4_reg_val, err6_reg_val;
++
++ /* loss dword syn, phy reset problem */
++ err4_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT4_REG);
++
++ /* disparity err, invalid dword */
++ err6_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT6_REG);
++
++ sphy->loss_of_dword_sync_count += (err4_reg_val >> 16) & 0xFFFF;
++ sphy->phy_reset_problem_count += err4_reg_val & 0xFFFF;
++ sphy->invalid_dword_count += (err6_reg_val & 0xFF0000) >> 16;
++ sphy->running_disparity_error_count += err6_reg_val & 0xFF;
++}
++
+ static void start_phys_v2_hw(struct hisi_hba *hisi_hba)
+ {
+ int i;
+@@ -3457,6 +3478,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
+ .phy_enable = enable_phy_v2_hw,
+ .phy_disable = disable_phy_v2_hw,
+ .phy_hard_reset = phy_hard_reset_v2_hw,
++ .get_events = phy_get_events_v2_hw,
+ .phy_set_linkrate = phy_set_linkrate_v2_hw,
+ .phy_get_max_linkrate = phy_get_max_linkrate_v2_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch b/patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch
new file mode 100644
index 0000000000..1434d54bff
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch
@@ -0,0 +1,81 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:27 +0800
+Subject: scsi: hisi_sas: avoid potential v2 hw interrupt issue
+Git-commit: c16db736653f5319d1d9b0d176f1f80394bd2614
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+When some interrupts happen together, we need to process every interrupt
+one-by-one, and should not return immediately when one interrupt process
+is finished being processed.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index a6be33c36e86..8c504b437567 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -2606,6 +2606,7 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+ struct hisi_hba *hisi_hba = p;
+ u32 irq_msk;
+ int phy_no = 0;
++ irqreturn_t res = IRQ_NONE;
+
+ irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
+ >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
+@@ -2620,15 +2621,15 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+ case CHL_INT0_SL_PHY_ENABLE_MSK:
+ /* phy up */
+ if (phy_up_v2_hw(phy_no, hisi_hba) ==
+- IRQ_NONE)
+- return IRQ_NONE;
++ IRQ_HANDLED)
++ res = IRQ_HANDLED;
+ break;
+
+ case CHL_INT0_NOT_RDY_MSK:
+ /* phy down */
+ if (phy_down_v2_hw(phy_no, hisi_hba) ==
+- IRQ_NONE)
+- return IRQ_NONE;
++ IRQ_HANDLED)
++ res = IRQ_HANDLED;
+ break;
+
+ case (CHL_INT0_NOT_RDY_MSK |
+@@ -2638,13 +2639,13 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+ if (reg_value & BIT(phy_no)) {
+ /* phy up */
+ if (phy_up_v2_hw(phy_no, hisi_hba) ==
+- IRQ_NONE)
+- return IRQ_NONE;
++ IRQ_HANDLED)
++ res = IRQ_HANDLED;
+ } else {
+ /* phy down */
+ if (phy_down_v2_hw(phy_no, hisi_hba) ==
+- IRQ_NONE)
+- return IRQ_NONE;
++ IRQ_HANDLED)
++ res = IRQ_HANDLED;
+ }
+ break;
+
+@@ -2657,7 +2658,7 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+ phy_no++;
+ }
+
+- return IRQ_HANDLED;
++ return res;
+ }
+
+ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch b/patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch
new file mode 100644
index 0000000000..e4de89e5c9
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch
@@ -0,0 +1,179 @@
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 14 Jun 2017 23:33:18 +0800
+Subject: scsi: hisi_sas: create hisi_sas_get_fw_info()
+Git-commit: 0fa24c19d844945b6edf981ff425c93f20085f10
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Move the functionality to retrieve the fw info into a dedicated device
+type-agnostic function, hisi_sas_get_fw_info().
+
+The reasoning is that this function will be required for future
+pci-based platforms.
+
+Also add some debug logs for failure.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 1 +
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 107 ++++++++++++++++++++++------------
+ 2 files changed, 71 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 84cac98b368a..c1f6669ab3f8 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -371,6 +371,7 @@ extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
+ extern void hisi_sas_sata_done(struct sas_task *task,
+ struct hisi_sas_slot *slot);
+ extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag);
++extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba);
+ extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+ extern int hisi_sas_remove(struct platform_device *pdev);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 139df4509a41..8a2af906e1ad 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -1729,66 +1729,99 @@ static void hisi_sas_rst_work_handler(struct work_struct *work)
+ hisi_sas_controller_reset(hisi_hba);
+ }
+
+-static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+- const struct hisi_sas_hw *hw)
++int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
+ {
+- struct resource *res;
+- struct Scsi_Host *shost;
+- struct hisi_hba *hisi_hba;
+- struct device *dev = &pdev->dev;
+- struct device_node *np = pdev->dev.of_node;
++ struct device *dev = hisi_hba->dev;
++ struct platform_device *pdev = hisi_hba->platform_dev;
++ struct device_node *np = pdev ? pdev->dev.of_node : NULL;
+ struct clk *refclk;
+
+- shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
+- if (!shost) {
+- dev_err(dev, "scsi host alloc failed\n");
+- return NULL;
+- }
+- hisi_hba = shost_priv(shost);
+-
+- INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
+- hisi_hba->hw = hw;
+- hisi_hba->platform_dev = pdev;
+- hisi_hba->dev = dev;
+- hisi_hba->shost = shost;
+- SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+-
+- init_timer(&hisi_hba->timer);
+-
+ if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
+- SAS_ADDR_SIZE))
+- goto err_out;
++ SAS_ADDR_SIZE)) {
++ dev_err(dev, "could not get property sas-addr\n");
++ return -ENOENT;
++ }
+
+ if (np) {
++ /*
++ * These properties are only required for platform device-based
++ * controller with DT firmware.
++ */
+ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
+ "hisilicon,sas-syscon");
+- if (IS_ERR(hisi_hba->ctrl))
+- goto err_out;
++ if (IS_ERR(hisi_hba->ctrl)) {
++ dev_err(dev, "could not get syscon\n");
++ return -ENOENT;
++ }
+
+ if (device_property_read_u32(dev, "ctrl-reset-reg",
+- &hisi_hba->ctrl_reset_reg))
+- goto err_out;
++ &hisi_hba->ctrl_reset_reg)) {
++ dev_err(dev,
++ "could not get property ctrl-reset-reg\n");
++ return -ENOENT;
++ }
+
+ if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
+- &hisi_hba->ctrl_reset_sts_reg))
+- goto err_out;
++ &hisi_hba->ctrl_reset_sts_reg)) {
++ dev_err(dev,
++ "could not get property ctrl-reset-sts-reg\n");
++ return -ENOENT;
++ }
+
+ if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
+- &hisi_hba->ctrl_clock_ena_reg))
+- goto err_out;
++ &hisi_hba->ctrl_clock_ena_reg)) {
++ dev_err(dev,
++ "could not get property ctrl-clock-ena-reg\n");
++ return -ENOENT;
++ }
+ }
+
+- refclk = devm_clk_get(&pdev->dev, NULL);
++ refclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(refclk))
+ dev_dbg(dev, "no ref clk property\n");
+ else
+ hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000;
+
+- if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy))
+- goto err_out;
++ if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) {
++ dev_err(dev, "could not get property phy-count\n");
++ return -ENOENT;
++ }
+
+ if (device_property_read_u32(dev, "queue-count",
+- &hisi_hba->queue_count))
++ &hisi_hba->queue_count)) {
++ dev_err(dev, "could not get property queue-count\n");
++ return -ENOENT;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(hisi_sas_get_fw_info);
++
++static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
++ const struct hisi_sas_hw *hw)
++{
++ struct resource *res;
++ struct Scsi_Host *shost;
++ struct hisi_hba *hisi_hba;
++ struct device *dev = &pdev->dev;
++
++ shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
++ if (!shost) {
++ dev_err(dev, "scsi host alloc failed\n");
++ return NULL;
++ }
++ hisi_hba = shost_priv(shost);
++
++ INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
++ hisi_hba->hw = hw;
++ hisi_hba->dev = dev;
++ hisi_hba->platform_dev = pdev;
++ hisi_hba->shost = shost;
++ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
++
++ init_timer(&hisi_hba->timer);
++
++ if (hisi_sas_get_fw_info(hisi_hba) < 0)
+ goto err_out;
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch b/patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch
new file mode 100644
index 0000000000..8dc58ef128
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch
@@ -0,0 +1,96 @@
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 14 Jun 2017 23:33:12 +0800
+Subject: scsi: hisi_sas: define hisi_sas_device.device_id as int
+Git-commit: ad6048325c7807818c6c49e485660143d97a622e
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Currently hisi_sas_device.device_id is a u64. This can create a problem
+in selecting the queue for a device, in that this code does a 64b
+division on device id. For some 32b systems, 64b division is slow and
+the lib reference must be explicitly included.
+
+The device id does not need to be 64b in size, so, as a solution, just
+make as an int.
+
+Also, struct hisi_sas_device elements are re-ordered to improve packing
+efficiency.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 8 ++++----
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 10 +++++-----
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 4e28f32e90b0..b4e96fa90bc2 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -107,15 +107,15 @@ struct hisi_sas_dq {
+ };
+
+ struct hisi_sas_device {
+- enum sas_device_type dev_type;
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
++ struct list_head list;
+ u64 attached_phy;
+- u64 device_id;
+ atomic64_t running_req;
+- struct list_head list;
+- u8 dev_status;
++ enum sas_device_type dev_type;
++ int device_id;
+ int sata_idx;
++ u8 dev_status;
+ };
+
+ struct hisi_sas_slot {
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 3605d28a2c60..54e0cf270c99 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -209,7 +209,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+
+ if (DEV_IS_GONE(sas_dev)) {
+ if (sas_dev)
+- dev_info(dev, "task prep: device %llu not ready\n",
++ dev_info(dev, "task prep: device %d not ready\n",
+ sas_dev->device_id);
+ else
+ dev_info(dev, "task prep: device %016llx not ready\n",
+@@ -627,9 +627,9 @@ static void hisi_sas_dev_gone(struct domain_device *device)
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+- u64 dev_id = sas_dev->device_id;
++ int dev_id = sas_dev->device_id;
+
+- dev_info(dev, "found dev[%lld:%x] is gone\n",
++ dev_info(dev, "found dev[%d:%x] is gone\n",
+ sas_dev->device_id, sas_dev->dev_type);
+
+ hisi_sas_internal_task_abort(hisi_hba, device,
+@@ -1082,7 +1082,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+ }
+ out:
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+- dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
++ dev_err(dev, "lu_reset: for device[%d]:rc= %d\n",
+ sas_dev->device_id, rc);
+ return rc;
+ }
+@@ -1129,7 +1129,7 @@ static int hisi_sas_query_task(struct sas_task *task)
+ }
+
+ static int
+-hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
++hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ struct sas_task *task, int abort_flag,
+ int task_tag)
+ {
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch b/patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch
new file mode 100644
index 0000000000..c9f44810e3
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch
@@ -0,0 +1,335 @@
+From: Xiaofei Tan <tanxiaofei@huawei.com>
+Date: Fri, 11 Aug 2017 00:09:26 +0800
+Subject: scsi: hisi_sas: fix reset and port ID refresh issues
+Git-commit: 917d3bdaf8f2ab3bace2bd60b78d83a2b3096d98
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+This patch provides fixes for the following issues:
+
+1. Fix issue of controller reset required to send commands. For reset
+ process, it may be required to send commands to the controller, but
+ not during soft reset. So add HISI_SAS_NOT_ACCEPT_CMD_BIT to prevent
+ executing a task during this period.
+
+2. Send a broadcast event in rescan topology to detect any topology
+ changes during reset.
+
+3. Previously it was not ensured that libsas has processed the PHY up
+ and down events after reset. Potentially this could cause an issue
+ that we still process the PHY event after reset. So resolve this by
+ flushing shot workqueue in LLDD reset.
+
+4. Port ID requires refresh after reset. The port ID generated after
+ reset is not guaranteed to be the same as before reset, so it needs
+ to be refreshed for each device's ITCT.
+
+Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 4 +-
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 152 ++++++++++++++++++++++-----------
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 36 ++++----
+ 3 files changed, 118 insertions(+), 74 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index a722f2bd72ab..3c4defad8c18 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -33,6 +33,7 @@
+ #define HISI_SAS_MAX_ITCT_ENTRIES 2048
+ #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+ #define HISI_SAS_RESET_BIT 0
++#define HISI_SAS_REJECT_CMD_BIT 1
+
+ #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer))
+ #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table))
+@@ -201,6 +202,7 @@ struct hisi_sas_hw {
+ void (*dereg_device)(struct hisi_hba *hisi_hba,
+ struct domain_device *device);
+ int (*soft_reset)(struct hisi_hba *hisi_hba);
++ u32 (*get_phys_state)(struct hisi_hba *hisi_hba);
+ int max_command_entries;
+ int complete_hdr_size;
+ };
+@@ -408,6 +410,4 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot);
+ extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
+-extern void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
+- u32 state);
+ #endif
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 4022c3f8295f..bd1d61958e10 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -433,7 +433,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_dq *dq = sas_dev->dq;
+
+- if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
++ if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
+ return -EINVAL;
+
+ /* protect task_prep and start_delivery sequence */
+@@ -967,37 +967,117 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ sizeof(ssp_task), tmf);
+ }
+
++static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba,
++ struct asd_sas_port *sas_port, enum sas_linkrate linkrate)
++{
++ struct hisi_sas_device *sas_dev;
++ struct domain_device *device;
++ int i;
++
++ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
++ sas_dev = &hisi_hba->devices[i];
++ device = sas_dev->sas_device;
++ if ((sas_dev->dev_type == SAS_PHY_UNUSED)
++ || !device || (device->port != sas_port))
++ continue;
++
++ hisi_hba->hw->free_device(hisi_hba, sas_dev);
++
++ /* Update linkrate of directly attached device. */
++ if (!device->parent)
++ device->linkrate = linkrate;
++
++ hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
++ }
++}
++
++static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
++ u32 state)
++{
++ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
++ struct asd_sas_port *_sas_port = NULL;
++ int phy_no;
++
++ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
++ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
++ struct asd_sas_phy *sas_phy = &phy->sas_phy;
++ struct asd_sas_port *sas_port = sas_phy->port;
++ struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
++ bool do_port_check = !!(_sas_port != sas_port);
++
++ if (!sas_phy->phy->enabled)
++ continue;
++
++ /* Report PHY state change to libsas */
++ if (state & (1 << phy_no)) {
++ if (do_port_check && sas_port) {
++ struct domain_device *dev = sas_port->port_dev;
++
++ _sas_port = sas_port;
++ port->id = phy->port_id;
++ hisi_sas_refresh_port_id(hisi_hba,
++ sas_port, sas_phy->linkrate);
++
++ if (DEV_IS_EXPANDER(dev->dev_type))
++ sas_ha->notify_port_event(sas_phy,
++ PORTE_BROADCAST_RCVD);
++ }
++ } else if (old_state & (1 << phy_no))
++ /* PHY down but was up before */
++ hisi_sas_phy_down(hisi_hba, phy_no, 0);
++
++ }
++
++ drain_workqueue(hisi_hba->shost->work_q);
++}
++
+ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
+ {
++ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
++ struct device *dev = hisi_hba->dev;
++ struct Scsi_Host *shost = hisi_hba->shost;
++ u32 old_state, state;
++ unsigned long flags;
+ int rc;
+
+ if (!hisi_hba->hw->soft_reset)
+ return -1;
+
+- if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+- struct device *dev = hisi_hba->dev;
+- struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+- unsigned long flags;
++ if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
++ return -1;
+
+- dev_dbg(dev, "controller reset begins!\n");
+- scsi_block_requests(hisi_hba->shost);
+- rc = hisi_hba->hw->soft_reset(hisi_hba);
+- if (rc) {
+- dev_warn(dev, "controller reset failed (%d)\n", rc);
+- goto out;
+- }
+- spin_lock_irqsave(&hisi_hba->lock, flags);
+- hisi_sas_release_tasks(hisi_hba);
+- spin_unlock_irqrestore(&hisi_hba->lock, flags);
++ dev_dbg(dev, "controller resetting...\n");
++ old_state = hisi_hba->hw->get_phys_state(hisi_hba);
+
+- sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+- dev_dbg(dev, "controller reset successful!\n");
+- } else
+- return -1;
++ scsi_block_requests(shost);
++ set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
++ rc = hisi_hba->hw->soft_reset(hisi_hba);
++ if (rc) {
++ dev_warn(dev, "controller reset failed (%d)\n", rc);
++ clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
++ goto out;
++ }
++ spin_lock_irqsave(&hisi_hba->lock, flags);
++ hisi_sas_release_tasks(hisi_hba);
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
++
++ sas_ha->notify_ha_event(sas_ha, HAE_RESET);
++ clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
++
++ /* Init and wait for PHYs to come up and all libsas event finished. */
++ hisi_hba->hw->phys_init(hisi_hba);
++ msleep(1000);
++ drain_workqueue(hisi_hba->wq);
++ drain_workqueue(shost->work_q);
++
++ state = hisi_hba->hw->get_phys_state(hisi_hba);
++ hisi_sas_rescan_topology(hisi_hba, old_state, state);
++ dev_dbg(dev, "controller reset complete\n");
+
+ out:
+- scsi_unblock_requests(hisi_hba->shost);
++ scsi_unblock_requests(shost);
+ clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
++
+ return rc;
+ }
+
+@@ -1241,7 +1321,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+ unsigned long flags, flags_dq;
+
+- if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
++ if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
+ return -EINVAL;
+
+ if (!device->port)
+@@ -1437,36 +1517,6 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
+ }
+ EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
+
+-void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
+- u32 state)
+-{
+- struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+- int phy_no;
+-
+- for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+- struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+- struct asd_sas_phy *sas_phy = &phy->sas_phy;
+- struct asd_sas_port *sas_port = sas_phy->port;
+- struct domain_device *dev;
+-
+- if (sas_phy->enabled) {
+- /* Report PHY state change to libsas */
+- if (state & (1 << phy_no))
+- continue;
+-
+- if (old_state & (1 << phy_no))
+- /* PHY down but was up before */
+- hisi_sas_phy_down(hisi_hba, phy_no, 0);
+- }
+- if (!sas_port)
+- continue;
+- dev = sas_port->port_dev;
+-
+- if (DEV_IS_EXPANDER(dev->dev_type))
+- sas_ha->notify_phy_event(sas_phy, PORTE_BROADCAST_RCVD);
+- }
+-}
+-EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology);
+
+ struct scsi_transport_template *hisi_sas_stt;
+ EXPORT_SYMBOL_GPL(hisi_sas_stt);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 2bfea7082e3a..a6be33c36e86 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -1364,8 +1364,15 @@ static void start_phys_v2_hw(struct hisi_hba *hisi_hba)
+ {
+ int i;
+
+- for (i = 0; i < hisi_hba->n_phy; i++)
++ for (i = 0; i < hisi_hba->n_phy; i++) {
++ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
++ struct asd_sas_phy *sas_phy = &phy->sas_phy;
++
++ if (!sas_phy->phy->enabled)
++ continue;
++
+ start_phy_v2_hw(hisi_hba, i);
++ }
+ }
+
+ static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
+@@ -3383,14 +3390,16 @@ static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
+ synchronize_irq(platform_get_irq(pdev, i));
+ }
+
++
++static u32 get_phys_state_v2_hw(struct hisi_hba *hisi_hba)
++{
++ return hisi_sas_read32(hisi_hba, PHY_STATE);
++}
++
+ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
+ {
+ struct device *dev = hisi_hba->dev;
+- u32 old_state, state;
+ int rc, cnt;
+- int phy_no;
+-
+- old_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ interrupt_disable_v2_hw(hisi_hba);
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+@@ -3425,22 +3434,6 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
+
+ phys_reject_stp_links_v2_hw(hisi_hba);
+
+- /* Re-enable the PHYs */
+- for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+- struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+- struct asd_sas_phy *sas_phy = &phy->sas_phy;
+-
+- if (sas_phy->enabled)
+- start_phy_v2_hw(hisi_hba, phy_no);
+- }
+-
+- /* Wait for the PHYs to come up and read the PHY state */
+- msleep(1000);
+-
+- state = hisi_sas_read32(hisi_hba, PHY_STATE);
+-
+- hisi_sas_rescan_topology(hisi_hba, old_state, state);
+-
+ return 0;
+ }
+
+@@ -3468,6 +3461,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
+ .soft_reset = soft_reset_v2_hw,
++ .get_phys_state = get_phys_state_v2_hw,
+ };
+
+ static int hisi_sas_v2_probe(struct platform_device *pdev)
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch b/patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch
new file mode 100644
index 0000000000..a1398ed0b2
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch
@@ -0,0 +1,73 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:11 +0800
+Subject: scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort()
+Git-commit: f64a6988268aae866bb6ce6edb910d454ccef331
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+We need to check for timeout before task status, or the task will be
+mistook as completed internal abort command. Also add protection for
+sas_task.task_state_flags in hisi_sas_tmf_timedout().
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index f720d3ced851..3605d28a2c60 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -691,8 +691,13 @@ static void hisi_sas_task_done(struct sas_task *task)
+ static void hisi_sas_tmf_timedout(unsigned long data)
+ {
+ struct sas_task *task = (struct sas_task *)data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
++ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+- task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->slow_task->completion);
+ }
+
+@@ -1247,6 +1252,17 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ wait_for_completion(&task->slow_task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+
++ /* Internal abort timed out */
++ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
++ struct hisi_sas_slot *slot = task->lldd_task;
++
++ if (slot)
++ slot->task = NULL;
++ dev_err(dev, "internal task abort: timeout.\n");
++ }
++ }
++
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
+ res = TMF_RESP_FUNC_COMPLETE;
+@@ -1259,13 +1275,6 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ goto exit;
+ }
+
+- /* Internal abort timed out */
+- if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+- if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+- dev_err(dev, "internal task abort: timeout.\n");
+- }
+- }
+-
+ exit:
+ dev_dbg(dev, "internal task abort: task to dev %016llx task=%p "
+ "resp: 0x%x sts 0x%x\n",
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch b/patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch
new file mode 100644
index 0000000000..c47da49881
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch
@@ -0,0 +1,44 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:28 +0800
+Subject: scsi: hisi_sas: fix v2 hw underflow residual value
+Git-commit: 01b361fc900dd8ef7f8537c20e3a1986ab63f4d1
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+The value dw0 is the residual bytes when UNDERFLOW error happens, but we
+filled the residual with the value of dw3 before. So change the residual
+from dw3 to dw0.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 8c504b437567..a762b259f68f 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -1972,7 +1972,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ }
+ case DMA_RX_DATA_LEN_UNDERFLOW:
+ {
+- ts->residual = dma_rx_err_type;
++ ts->residual = trans_tx_fail_type;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+@@ -2098,7 +2098,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ }
+ case DMA_RX_DATA_LEN_UNDERFLOW:
+ {
+- ts->residual = dma_rx_err_type;
++ ts->residual = trans_tx_fail_type;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch b/patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch
new file mode 100644
index 0000000000..1c9a81a79e
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch
@@ -0,0 +1,78 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Tue, 11 Jul 2017 13:11:44 +0100
+Subject: scsi: hisi_sas: make several const arrays static
+Git-commit: 89b203e9d07d4079367120a6fe271ad9e9b751c0
+Patch-mainline: v4.13-rc2
+References: bsc#1068693
+
+Don't populate various tables on the stack but make them static const.
+Makes the object code smaller by over 280 bytes:
+
+Before:
+ text data bss dec hex filename
+ 39887 5080 64 45031 afe7 hisi_sas_v2_hw.o
+
+After:
+ text data bss dec hex filename
+ 39318 5368 64 44750 aece hisi_sas_v2_hw.o
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Acked-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 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 551d103c27f1..2bfea7082e3a 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -1693,7 +1693,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+
+ static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
+ {
+- const u8 trans_tx_err_code_prio[] = {
++ static const u8 trans_tx_err_code_prio[] = {
+ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
+ TRANS_TX_ERR_PHY_NOT_ENABLE,
+ TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
+@@ -1738,7 +1738,7 @@ static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
+
+ static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
+ {
+- const u8 trans_rx_err_code_prio[] = {
++ static const u8 trans_rx_err_code_prio[] = {
+ TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
+ TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
+ TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
+@@ -1784,7 +1784,7 @@ static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
+
+ static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
+ {
+- const u8 dma_tx_err_code_prio[] = {
++ static const u8 dma_tx_err_code_prio[] = {
+ DMA_TX_UNEXP_XFER_ERR,
+ DMA_TX_UNEXP_RETRANS_ERR,
+ DMA_TX_XFER_LEN_OVERFLOW,
+@@ -1810,7 +1810,7 @@ static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
+
+ static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
+ {
+- const u8 sipc_rx_err_code_prio[] = {
++ static const u8 sipc_rx_err_code_prio[] = {
+ SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
+ SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
+ SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
+@@ -1836,7 +1836,7 @@ static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
+
+ static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
+ {
+- const u8 dma_rx_err_code_prio[] = {
++ static const u8 dma_rx_err_code_prio[] = {
+ DMA_RX_UNKNOWN_FRM_ERR,
+ DMA_RX_DATA_LEN_OVERFLOW,
+ DMA_RX_DATA_LEN_UNDERFLOW,
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch b/patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch
new file mode 100644
index 0000000000..54120bf856
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch
@@ -0,0 +1,568 @@
+From: Xiaofei Tan <tanxiaofei@huawei.com>
+Date: Thu, 29 Jun 2017 21:02:14 +0800
+Subject: scsi: hisi_sas: optimise DMA slot memory
+Git-commit: f557e32c0023ea0d67cdaa81b3398550dc1e4876
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Currently we allocate 3 sets of DMA memories from separate pools for
+each slot. This is inefficient in terms of memory usage
+(buffers are less than 1 page in size, so we lose due to alignment),
+and also time spent in doing 3 allocations + de-allocations per slot,
+instead of 1.
+
+To optimise, combine the 3 DMA buffers into a single buffer from a
+single pool.
+
+Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 47 ++++++++++++++-------
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 75 +++++++++-------------------------
+ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 31 +++++++-------
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 37 ++++++++---------
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 36 ++++++++--------
+ 5 files changed, 104 insertions(+), 122 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 22dd48bc2fa0..a722f2bd72ab 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -34,10 +34,24 @@
+ #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+ #define HISI_SAS_RESET_BIT 0
+
+-#define HISI_SAS_STATUS_BUF_SZ \
+- (sizeof(struct hisi_sas_err_record) + 1024)
+-#define HISI_SAS_COMMAND_TABLE_SZ \
+- (((sizeof(union hisi_sas_command_table)+3)/4)*4)
++#define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer))
++#define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table))
++
++#define hisi_sas_status_buf_addr(buf) \
++ (buf + offsetof(struct hisi_sas_slot_buf_table, status_buffer))
++#define hisi_sas_status_buf_addr_mem(slot) hisi_sas_status_buf_addr(slot->buf)
++#define hisi_sas_status_buf_addr_dma(slot) \
++ hisi_sas_status_buf_addr(slot->buf_dma)
++
++#define hisi_sas_cmd_hdr_addr(buf) \
++ (buf + offsetof(struct hisi_sas_slot_buf_table, command_header))
++#define hisi_sas_cmd_hdr_addr_mem(slot) hisi_sas_cmd_hdr_addr(slot->buf)
++#define hisi_sas_cmd_hdr_addr_dma(slot) hisi_sas_cmd_hdr_addr(slot->buf_dma)
++
++#define hisi_sas_sge_addr(buf) \
++ (buf + offsetof(struct hisi_sas_slot_buf_table, sge_page))
++#define hisi_sas_sge_addr_mem(slot) hisi_sas_sge_addr(slot->buf)
++#define hisi_sas_sge_addr_dma(slot) hisi_sas_sge_addr(slot->buf_dma)
+
+ #define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
+ #define HISI_SAS_MAX_SMP_RESP_SZ 1028
+@@ -139,14 +153,10 @@ struct hisi_sas_slot {
+ int cmplt_queue_slot;
+ int idx;
+ int abort;
++ void *buf;
++ dma_addr_t buf_dma;
+ void *cmd_hdr;
+ dma_addr_t cmd_hdr_dma;
+- void *status_buffer;
+- dma_addr_t status_buffer_dma;
+- void *command_table;
+- dma_addr_t command_table_dma;
+- struct hisi_sas_sge_page *sge_page;
+- dma_addr_t sge_page_dma;
+ struct work_struct abort_slot;
+ struct timer_list internal_abort_timer;
+ };
+@@ -232,10 +242,8 @@ struct hisi_hba {
+
+ int queue_count;
+
+- struct dma_pool *sge_page_pool;
++ struct dma_pool *buffer_pool;
+ struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES];
+- struct dma_pool *command_table_pool;
+- struct dma_pool *status_buffer_pool;
+ struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES];
+ void *complete_hdr[HISI_SAS_MAX_QUEUES];
+@@ -347,7 +355,7 @@ struct hisi_sas_command_table_stp {
+ #define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE
+ struct hisi_sas_sge_page {
+ struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
+-};
++} __aligned(16);
+
+ struct hisi_sas_command_table_ssp {
+ struct ssp_frame_hdr hdr;
+@@ -366,6 +374,17 @@ union hisi_sas_command_table {
+ struct hisi_sas_command_table_ssp ssp;
+ struct hisi_sas_command_table_smp smp;
+ struct hisi_sas_command_table_stp stp;
++} __aligned(16);
++
++struct hisi_sas_status_buffer {
++ struct hisi_sas_err_record err;
++ u8 iu[1024];
++} __aligned(16);
++
++struct hisi_sas_slot_buf_table {
++ struct hisi_sas_status_buffer status_buffer;
++ union hisi_sas_command_table command_header;
++ struct hisi_sas_sge_page sge_page;
+ };
+
+ extern struct scsi_transport_template *hisi_sas_stt;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index e2f8d928e579..4022c3f8295f 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -87,8 +87,10 @@ void hisi_sas_sata_done(struct sas_task *task,
+ {
+ struct task_status_struct *ts = &task->task_status;
+ struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+- struct dev_to_host_fis *d2h = slot->status_buffer +
+- sizeof(struct hisi_sas_err_record);
++ struct hisi_sas_status_buffer *status_buf =
++ hisi_sas_status_buf_addr_mem(slot);
++ u8 *iu = &status_buf->iu[0];
++ struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu;
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+@@ -183,17 +185,9 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+ atomic64_dec(&sas_dev->running_req);
+ }
+
+- if (slot->command_table)
+- dma_pool_free(hisi_hba->command_table_pool,
+- slot->command_table, slot->command_table_dma);
++ if (slot->buf)
++ dma_pool_free(hisi_hba->buffer_pool, slot->buf, slot->buf_dma);
+
+- if (slot->status_buffer)
+- dma_pool_free(hisi_hba->status_buffer_pool,
+- slot->status_buffer, slot->status_buffer_dma);
+-
+- if (slot->sge_page)
+- dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+- slot->sge_page_dma);
+
+ list_del_init(&slot->entry);
+ slot->task = NULL;
+@@ -362,24 +356,15 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+ task->lldd_task = slot;
+ INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort);
+
+- slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
+- GFP_ATOMIC,
+- &slot->status_buffer_dma);
+- if (!slot->status_buffer) {
++ slot->buf = dma_pool_alloc(hisi_hba->buffer_pool,
++ GFP_ATOMIC, &slot->buf_dma);
++ if (!slot->buf) {
+ rc = -ENOMEM;
+ goto err_out_slot_buf;
+ }
+- memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
+-
+- slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
+- GFP_ATOMIC,
+- &slot->command_table_dma);
+- if (!slot->command_table) {
+- rc = -ENOMEM;
+- goto err_out_status_buf;
+- }
+- memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
++ memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
++ memset(hisi_sas_status_buf_addr_mem(slot), 0, HISI_SAS_STATUS_BUF_SZ);
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+@@ -402,9 +387,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+
+ if (rc) {
+ dev_err(dev, "task prep: rc = 0x%x\n", rc);
+- if (slot->sge_page)
+- goto err_out_sge;
+- goto err_out_command_table;
++ goto err_out_buf;
+ }
+
+ list_add_tail(&slot->entry, &sas_dev->list);
+@@ -419,15 +402,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+
+ return 0;
+
+-err_out_sge:
+- dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+- slot->sge_page_dma);
+-err_out_command_table:
+- dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
+- slot->command_table_dma);
+-err_out_status_buf:
+- dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
+- slot->status_buffer_dma);
++err_out_buf:
++ dma_pool_free(hisi_hba->buffer_pool, slot->buf,
++ slot->buf_dma);
+ err_out_slot_buf:
+ /* Nothing to be done */
+ err_out_tag:
+@@ -1608,16 +1585,9 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+ goto err_out;
+ }
+
+- s = HISI_SAS_STATUS_BUF_SZ;
+- hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
+- dev, s, 16, 0);
+- if (!hisi_hba->status_buffer_pool)
+- goto err_out;
+-
+- s = HISI_SAS_COMMAND_TABLE_SZ;
+- hisi_hba->command_table_pool = dma_pool_create("command_table",
+- dev, s, 16, 0);
+- if (!hisi_hba->command_table_pool)
++ s = sizeof(struct hisi_sas_slot_buf_table);
++ hisi_hba->buffer_pool = dma_pool_create("dma_buffer", dev, s, 16, 0);
++ if (!hisi_hba->buffer_pool)
+ goto err_out;
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+@@ -1652,11 +1622,6 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+ if (!hisi_hba->slot_index_tags)
+ goto err_out;
+
+- hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
+- sizeof(struct hisi_sas_sge_page), 16, 0);
+- if (!hisi_hba->sge_page_pool)
+- goto err_out;
+-
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
+ &hisi_hba->initial_fis_dma, GFP_KERNEL);
+@@ -1703,9 +1668,7 @@ void hisi_sas_free(struct hisi_hba *hisi_hba)
+ hisi_hba->complete_hdr_dma[i]);
+ }
+
+- dma_pool_destroy(hisi_hba->status_buffer_pool);
+- dma_pool_destroy(hisi_hba->command_table_pool);
+- dma_pool_destroy(hisi_hba->sge_page_pool);
++ dma_pool_destroy(hisi_hba->buffer_pool);
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ if (hisi_hba->itct)
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+index afa87d4c367a..08eca20b0b81 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+@@ -939,6 +939,7 @@ static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ struct scatterlist *scatter,
+ int n_elem)
+ {
++ struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
+ struct device *dev = hisi_hba->dev;
+ struct scatterlist *sg;
+ int i;
+@@ -949,13 +950,8 @@ static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ return -EINVAL;
+ }
+
+- slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+- &slot->sge_page_dma);
+- if (!slot->sge_page)
+- return -ENOMEM;
+-
+ for_each_sg(scatter, sg, n_elem, i) {
+- struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
++ struct hisi_sas_sge *entry = &sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+@@ -963,7 +959,7 @@ static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ entry->data_off = 0;
+ }
+
+- hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
++ hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+@@ -1026,7 +1022,7 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+ return 0;
+
+@@ -1107,10 +1103,11 @@ static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+- hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+- buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
++ buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) +
++ sizeof(struct ssp_frame_hdr);
+ if (task->ssp_task.enable_first_burst) {
+ fburst = (1 << 7);
+ dw2 |= 1 << CMD_HDR_FIRST_BURST_OFF;
+@@ -1147,7 +1144,8 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+ {
+ struct task_status_struct *ts = &task->task_status;
+- struct hisi_sas_err_record_v1 *err_record = slot->status_buffer;
++ struct hisi_sas_err_record_v1 *err_record =
++ hisi_sas_status_buf_addr_mem(slot);
+ struct device *dev = hisi_hba->dev;
+
+ switch (task->task_proto) {
+@@ -1364,8 +1362,11 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+- struct ssp_response_iu *iu = slot->status_buffer +
+- sizeof(struct hisi_sas_err_record);
++ struct hisi_sas_status_buffer *status_buffer =
++ hisi_sas_status_buf_addr_mem(slot);
++ struct ssp_response_iu *iu = (struct ssp_response_iu *)
++ &status_buffer->iu[0];
++
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+@@ -1382,7 +1383,7 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+- slot->status_buffer +
++ hisi_sas_status_buf_addr_mem(slot) +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 341a0bf6c667..551d103c27f1 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -1492,6 +1492,7 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ struct scatterlist *scatter,
+ int n_elem)
+ {
++ struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
+ struct device *dev = hisi_hba->dev;
+ struct scatterlist *sg;
+ int i;
+@@ -1502,13 +1503,8 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ return -EINVAL;
+ }
+
+- slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+- &slot->sge_page_dma);
+- if (!slot->sge_page)
+- return -ENOMEM;
+-
+ for_each_sg(scatter, sg, n_elem, i) {
+- struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
++ struct hisi_sas_sge *entry = &sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+@@ -1516,7 +1512,7 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ entry->data_off = 0;
+ }
+
+- hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
++ hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+@@ -1580,7 +1576,7 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+ return 0;
+
+@@ -1654,10 +1650,11 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+- hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+- buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
++ buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) +
++ sizeof(struct ssp_frame_hdr);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+@@ -1884,7 +1881,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ int err_phase)
+ {
+ struct task_status_struct *ts = &task->task_status;
+- struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
++ struct hisi_sas_err_record_v2 *err_record =
++ hisi_sas_status_buf_addr_mem(slot);
+ u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
+ u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
+@@ -2273,8 +2271,10 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+- struct ssp_response_iu *iu = slot->status_buffer +
+- sizeof(struct hisi_sas_err_record);
++ struct hisi_sas_status_buffer *status_buffer =
++ hisi_sas_status_buf_addr_mem(slot);
++ struct ssp_response_iu *iu = (struct ssp_response_iu *)
++ &status_buffer->iu[0];
+
+ sas_ssp_task_response(dev, task, iu);
+ break;
+@@ -2292,7 +2292,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+- slot->status_buffer +
++ hisi_sas_status_buf_addr_mem(slot) +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+@@ -2398,12 +2398,11 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ return rc;
+ }
+
+-
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+- hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+- buf_cmd = slot->command_table;
++ buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot);
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index c998b81f33de..83d2dca1c650 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -743,6 +743,7 @@ static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
+ struct scatterlist *scatter,
+ int n_elem)
+ {
++ struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
+ struct device *dev = hisi_hba->dev;
+ struct scatterlist *sg;
+ int i;
+@@ -753,13 +754,8 @@ static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
+ return -EINVAL;
+ }
+
+- slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+- &slot->sge_page_dma);
+- if (!slot->sge_page)
+- return -ENOMEM;
+-
+ for_each_sg(scatter, sg, n_elem, i) {
+- struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
++ struct hisi_sas_sge *entry = &sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+@@ -767,7 +763,8 @@ static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
+ entry->data_off = 0;
+ }
+
+- hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
++ hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
++
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+@@ -833,12 +830,13 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+- hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+- buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+- memcpy(buf_cmd, ssp_task->LUN, 8);
++ buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) +
++ sizeof(struct ssp_frame_hdr);
+
++ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = ssp_task->task_attr | (ssp_task->task_prio << 3);
+ memcpy(buf_cmd + 12, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
+@@ -917,7 +915,7 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+ return 0;
+
+@@ -1012,10 +1010,10 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+- hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+- hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
++ hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
++ hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
+
+- buf_cmd = slot->command_table;
++ buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot);
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+@@ -1283,7 +1281,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v3_hdr *complete_hdr =
+ &complete_queue[slot->cmplt_queue_slot];
+- struct hisi_sas_err_record_v3 *record = slot->status_buffer;
++ struct hisi_sas_err_record_v3 *record =
++ hisi_sas_status_buf_addr_mem(slot);
+ u32 dma_rx_err_type = record->dma_rx_err_type;
+ u32 trans_tx_fail_type = record->trans_tx_fail_type;
+
+@@ -1402,7 +1401,8 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP: {
+- struct ssp_response_iu *iu = slot->status_buffer +
++ struct ssp_response_iu *iu =
++ hisi_sas_status_buf_addr_mem(slot) +
+ sizeof(struct hisi_sas_err_record);
+
+ sas_ssp_task_response(dev, task, iu);
+@@ -1420,7 +1420,7 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+- slot->status_buffer +
++ hisi_sas_status_buf_addr_mem(slot) +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch b/patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch
new file mode 100644
index 0000000000..a59a2fdf61
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch
@@ -0,0 +1,424 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:13 +0800
+Subject: scsi: hisi_sas: optimise the usage of hisi_hba.lock
+Git-commit: b1a49412f0aed757e7632f9276acdf2fb8f3832e
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Currently hisi_hba.lock is locked to deliver and receive a command
+to/from any hw queue. This causes much contention at high data-rates.
+
+To boost performance, lock on a per queue basis for sending and
+receiving commands to/from hw.
+
+Certain critical regions still need to be locked in the delivery and
+completion stages with hisi_hba.lock.
+
+New element hisi_sas_device.dq is added to store the delivery queue for
+a device, so it does not need to be needlessly re-calculated for every
+task.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 9 +++--
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 69 +++++++++++++++++++++++-----------
+ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 23 ++++--------
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 34 ++++++++---------
+ 4 files changed, 77 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index b4e96fa90bc2..68ba7bd229e8 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -102,6 +102,8 @@ struct hisi_sas_cq {
+
+ struct hisi_sas_dq {
+ struct hisi_hba *hisi_hba;
++ struct hisi_sas_slot *slot_prep;
++ spinlock_t lock;
+ int wr_point;
+ int id;
+ };
+@@ -109,6 +111,7 @@ struct hisi_sas_dq {
+ struct hisi_sas_device {
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
++ struct hisi_sas_dq *dq;
+ struct list_head list;
+ u64 attached_phy;
+ atomic64_t running_req;
+@@ -154,9 +157,8 @@ struct hisi_sas_hw {
+ struct domain_device *device);
+ struct hisi_sas_device *(*alloc_dev)(struct domain_device *device);
+ void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
+- int (*get_free_slot)(struct hisi_hba *hisi_hba, u32 dev_id,
+- int *q, int *s);
+- void (*start_delivery)(struct hisi_hba *hisi_hba);
++ int (*get_free_slot)(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq);
++ void (*start_delivery)(struct hisi_sas_dq *dq);
+ int (*prep_ssp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf);
+@@ -217,7 +219,6 @@ struct hisi_hba {
+ struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
+
+ int queue_count;
+- struct hisi_sas_slot *slot_prep;
+
+ struct dma_pool *sge_page_pool;
+ struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES];
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 54e0cf270c99..4e78cbcd0cf2 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -179,10 +179,11 @@ static void hisi_sas_slot_abort(struct work_struct *work)
+ task->task_done(task);
+ }
+
+-static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+- int is_tmf, struct hisi_sas_tmf_task *tmf,
+- int *pass)
++static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
++ *dq, int is_tmf, struct hisi_sas_tmf_task *tmf,
++ int *pass)
+ {
++ struct hisi_hba *hisi_hba = dq->hisi_hba;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port;
+@@ -240,18 +241,24 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ } else
+ n_elem = task->num_scatter;
+
++ spin_lock_irqsave(&hisi_hba->lock, flags);
+ if (hisi_hba->hw->slot_index_alloc)
+ rc = hisi_hba->hw->slot_index_alloc(hisi_hba, &slot_idx,
+ device);
+ else
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+- if (rc)
++ if (rc) {
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ goto err_out;
+- rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
+- &dlvry_queue, &dlvry_queue_slot);
++ }
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
++
++ rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
+ if (rc)
+ goto err_out_tag;
+
++ dlvry_queue = dq->id;
++ dlvry_queue_slot = dq->wr_point;
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+@@ -316,7 +323,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+- hisi_hba->slot_prep = slot;
++ dq->slot_prep = slot;
+
+ atomic64_inc(&sas_dev->running_req);
+ ++(*pass);
+@@ -335,7 +342,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ err_out_slot_buf:
+ /* Nothing to be done */
+ err_out_tag:
++ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ err_out:
+ dev_err(dev, "task prep: failed[%d]!\n", rc);
+ if (!sas_protocol_ata(task->task_proto))
+@@ -354,19 +363,22 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ unsigned long flags;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
++ struct domain_device *device = task->dev;
++ struct hisi_sas_device *sas_dev = device->lldd_dev;
++ struct hisi_sas_dq *dq = sas_dev->dq;
+
+ if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
+ return -EINVAL;
+
+ /* protect task_prep and start_delivery sequence */
+- spin_lock_irqsave(&hisi_hba->lock, flags);
+- rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
++ spin_lock_irqsave(&dq->lock, flags);
++ rc = hisi_sas_task_prep(task, dq, is_tmf, tmf, &pass);
+ if (rc)
+ dev_err(dev, "task exec: failed[%d]!\n", rc);
+
+ if (likely(pass))
+- hisi_hba->hw->start_delivery(hisi_hba);
+- spin_unlock_irqrestore(&hisi_hba->lock, flags);
++ hisi_hba->hw->start_delivery(dq);
++ spin_unlock_irqrestore(&dq->lock, flags);
+
+ return rc;
+ }
+@@ -421,12 +433,16 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
+ spin_lock(&hisi_hba->lock);
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
++ int queue = i % hisi_hba->queue_count;
++ struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
++
+ hisi_hba->devices[i].device_id = i;
+ sas_dev = &hisi_hba->devices[i];
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ sas_dev->dev_type = device->dev_type;
+ sas_dev->hisi_hba = hisi_hba;
+ sas_dev->sas_device = device;
++ sas_dev->dq = dq;
+ INIT_LIST_HEAD(&hisi_hba->devices[i].list);
+ break;
+ }
+@@ -1140,8 +1156,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ struct hisi_sas_slot *slot;
+ struct asd_sas_port *sas_port = device->port;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
++ struct hisi_sas_dq *dq = sas_dev->dq;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+- unsigned long flags;
++ unsigned long flags, flags_dq;
+
+ if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
+ return -EINVAL;
+@@ -1152,14 +1169,22 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ port = to_hisi_sas_port(sas_port);
+
+ /* simply get a slot and send abort command */
++ spin_lock_irqsave(&hisi_hba->lock, flags);
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+- if (rc)
++ if (rc) {
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ goto err_out;
+- rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
+- &dlvry_queue, &dlvry_queue_slot);
++ }
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
++
++ spin_lock_irqsave(&dq->lock, flags_dq);
++ rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
+ if (rc)
+ goto err_out_tag;
+
++ dlvry_queue = dq->id;
++ dlvry_queue_slot = dq->wr_point;
++
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+@@ -1186,17 +1211,21 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+- hisi_hba->slot_prep = slot;
++ dq->slot_prep = slot;
+
+ atomic64_inc(&sas_dev->running_req);
+
+- /* send abort command to our chip */
+- hisi_hba->hw->start_delivery(hisi_hba);
++ /* send abort command to the chip */
++ hisi_hba->hw->start_delivery(dq);
++ spin_unlock_irqrestore(&dq->lock, flags_dq);
+
+ return 0;
+
+ err_out_tag:
++ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
++ spin_unlock_irqrestore(&dq->lock, flags_dq);
+ err_out:
+ dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
+
+@@ -1221,7 +1250,6 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int res;
+- unsigned long flags;
+
+ if (!hisi_hba->hw->prep_abort)
+ return -EOPNOTSUPP;
+@@ -1238,11 +1266,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110);
+ add_timer(&task->slow_task->timer);
+
+- /* Lock as we are alloc'ing a slot, which cannot be interrupted */
+- spin_lock_irqsave(&hisi_hba->lock, flags);
+ res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
+ task, abort_flag, tag);
+- spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ if (res) {
+ del_timer(&task->slow_task->timer);
+ dev_err(dev, "internal task abort: executing internal task failed: %d\n",
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+index fc1c1b2c1a19..7d7d2a7e690d 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+@@ -900,22 +900,17 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+ return bitmap;
+ }
+
+-/**
+- * This function allocates across all queues to load balance.
+- * Slots are allocated from queues in a round-robin fashion.
+- *
++/*
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+-static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+- int *q, int *s)
++static int
++get_free_slot_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+ {
+ struct device *dev = &hisi_hba->pdev->dev;
+- struct hisi_sas_dq *dq;
++ int queue = dq->id;
+ u32 r, w;
+- int queue = dev_id % hisi_hba->queue_count;
+
+- dq = &hisi_hba->dq[queue];
+ w = dq->wr_point;
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+@@ -924,16 +919,14 @@ static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+ return -EAGAIN;
+ }
+
+- *q = queue;
+- *s = w;
+ return 0;
+ }
+
+-static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
++static void start_delivery_v1_hw(struct hisi_sas_dq *dq)
+ {
+- int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+- int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+- struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue];
++ struct hisi_hba *hisi_hba = dq->hisi_hba;
++ int dlvry_queue = dq->slot_prep->dlvry_queue;
++ int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+
+ dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index e241921bee10..2607aac00ac9 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -695,6 +695,9 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
+ if (sata_dev && (i & 1))
+ continue;
+ if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
++ int queue = i % hisi_hba->queue_count;
++ struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
++
+ hisi_hba->devices[i].device_id = i;
+ sas_dev = &hisi_hba->devices[i];
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+@@ -702,6 +705,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
+ sas_dev->hisi_hba = hisi_hba;
+ sas_dev->sas_device = device;
+ sas_dev->sata_idx = sata_idx;
++ sas_dev->dq = dq;
+ INIT_LIST_HEAD(&hisi_hba->devices[i].list);
+ break;
+ }
+@@ -1454,22 +1458,17 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
+ return bitmap;
+ }
+
+-/**
+- * This function allocates across all queues to load balance.
+- * Slots are allocated from queues in a round-robin fashion.
+- *
++/*
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+-static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+- int *q, int *s)
++static int
++get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+ {
+ struct device *dev = &hisi_hba->pdev->dev;
+- struct hisi_sas_dq *dq;
++ int queue = dq->id;
+ u32 r, w;
+- int queue = dev_id % hisi_hba->queue_count;
+
+- dq = &hisi_hba->dq[queue];
+ w = dq->wr_point;
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+@@ -1479,16 +1478,14 @@ static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+ return -EAGAIN;
+ }
+
+- *q = queue;
+- *s = w;
+ return 0;
+ }
+
+-static void start_delivery_v2_hw(struct hisi_hba *hisi_hba)
++static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
+ {
+- int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+- int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+- struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue];
++ struct hisi_hba *hisi_hba = dq->hisi_hba;
++ int dlvry_queue = dq->slot_prep->dlvry_queue;
++ int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+
+ dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+@@ -2344,7 +2341,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
++ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ sts = ts->stat;
+
+ if (task->task_done)
+@@ -3162,13 +3161,14 @@ static void cq_tasklet_v2_hw(unsigned long val)
+ struct hisi_sas_complete_v2_hdr *complete_queue;
+ u32 rd_point = cq->rd_point, wr_point, dev_id;
+ int queue = cq->id;
++ struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
+
+ if (unlikely(hisi_hba->reject_stp_links_msk))
+ phys_try_accept_stp_links_v2_hw(hisi_hba);
+
+ complete_queue = hisi_hba->complete_hdr[queue];
+
+- spin_lock(&hisi_hba->lock);
++ spin_lock(&dq->lock);
+ wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
+ (0x14 * queue));
+
+@@ -3218,7 +3218,7 @@ static void cq_tasklet_v2_hw(unsigned long val)
+ /* update rd_point */
+ cq->rd_point = rd_point;
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+- spin_unlock(&hisi_hba->lock);
++ spin_unlock(&dq->lock);
+ }
+
+ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch b/patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch
new file mode 100644
index 0000000000..eafc728ee6
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch
@@ -0,0 +1,43 @@
+From: John Garry <john.garry@huawei.com>
+Date: Mon, 26 Jun 2017 18:27:28 +0800
+Subject: scsi: hisi_sas: redefine hisi_sas_phy.phy_type as u32
+Git-commit: d0ef10c9a42ee2008a5106d04ed34a53b9c6e6c6
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Element phy_type is a bitmask and it only ever has 2 bits possibly set,
+and it is overkill to define as a u64, so redefine as a u32.
+
+This change resolves static code check complaint that "phy->phy_type &=
+~PORT_TYPE_SAS;" would unintentionally clear the high 32 bits as well.
+
+Structure hisi_sas_phy is also reordered to ensure packing efficiency.
+
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ 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 4fc23087a939..22dd48bc2fa0 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -85,11 +85,11 @@ struct hisi_sas_phy {
+ struct work_struct phyup_ws;
+ u64 port_id; /* from hw */
+ u64 dev_sas_addr;
+- u64 phy_type;
+ u64 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+ u8 reserved[3];
++ u32 phy_type;
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate;
+ };
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch b/patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch
new file mode 100644
index 0000000000..7612b80142
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch
@@ -0,0 +1,210 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:14 +0800
+Subject: scsi: hisi_sas: relocate get_ata_protocol()
+Git-commit: 6c7bb8a1942a2a11b77f208910fc57047c62c77b
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Relocate get_ata_protocol() to a common location, as future hw versions
+will require it. Also rename with "hisi_sas_" prefix for consistency.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 7 ++++
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 59 ++++++++++++++++++++++++++++++
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 67 +---------------------------------
+ 3 files changed, 68 insertions(+), 65 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 68ba7bd229e8..a50c69989352 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -46,6 +46,12 @@
+ ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+ (type == SAS_FANOUT_EXPANDER_DEVICE))
+
++#define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1
++#define HISI_SAS_SATA_PROTOCOL_PIO 0x2
++#define HISI_SAS_SATA_PROTOCOL_DMA 0x4
++#define HISI_SAS_SATA_PROTOCOL_FPDMA 0x8
++#define HISI_SAS_SATA_PROTOCOL_ATAPI 0x10
++
+ struct hisi_hba;
+
+ enum {
+@@ -356,6 +362,7 @@ union hisi_sas_command_table {
+ struct hisi_sas_command_table_stp stp;
+ };
+
++extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
+ extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
+ extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 4e78cbcd0cf2..5b51d9af2013 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -23,6 +23,65 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ int abort_flag, int tag);
+ static int hisi_sas_softreset_ata_disk(struct domain_device *device);
+
++u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
++{
++ switch (cmd) {
++ case ATA_CMD_FPDMA_WRITE:
++ case ATA_CMD_FPDMA_READ:
++ case ATA_CMD_FPDMA_RECV:
++ case ATA_CMD_FPDMA_SEND:
++ case ATA_CMD_NCQ_NON_DATA:
++ return HISI_SAS_SATA_PROTOCOL_FPDMA;
++
++ case ATA_CMD_DOWNLOAD_MICRO:
++ case ATA_CMD_ID_ATA:
++ case ATA_CMD_PMP_READ:
++ case ATA_CMD_READ_LOG_EXT:
++ case ATA_CMD_PIO_READ:
++ case ATA_CMD_PIO_READ_EXT:
++ case ATA_CMD_PMP_WRITE:
++ case ATA_CMD_WRITE_LOG_EXT:
++ case ATA_CMD_PIO_WRITE:
++ case ATA_CMD_PIO_WRITE_EXT:
++ return HISI_SAS_SATA_PROTOCOL_PIO;
++
++ case ATA_CMD_DSM:
++ case ATA_CMD_DOWNLOAD_MICRO_DMA:
++ case ATA_CMD_PMP_READ_DMA:
++ case ATA_CMD_PMP_WRITE_DMA:
++ case ATA_CMD_READ:
++ case ATA_CMD_READ_EXT:
++ case ATA_CMD_READ_LOG_DMA_EXT:
++ case ATA_CMD_READ_STREAM_DMA_EXT:
++ case ATA_CMD_TRUSTED_RCV_DMA:
++ case ATA_CMD_TRUSTED_SND_DMA:
++ case ATA_CMD_WRITE:
++ case ATA_CMD_WRITE_EXT:
++ case ATA_CMD_WRITE_FUA_EXT:
++ case ATA_CMD_WRITE_QUEUED:
++ case ATA_CMD_WRITE_LOG_DMA_EXT:
++ case ATA_CMD_WRITE_STREAM_DMA_EXT:
++ return HISI_SAS_SATA_PROTOCOL_DMA;
++
++ case ATA_CMD_CHK_POWER:
++ case ATA_CMD_DEV_RESET:
++ case ATA_CMD_EDD:
++ case ATA_CMD_FLUSH:
++ case ATA_CMD_FLUSH_EXT:
++ case ATA_CMD_VERIFY:
++ case ATA_CMD_VERIFY_EXT:
++ case ATA_CMD_SET_FEATURES:
++ case ATA_CMD_STANDBY:
++ case ATA_CMD_STANDBYNOW1:
++ return HISI_SAS_SATA_PROTOCOL_NONDATA;
++ default:
++ if (direction == DMA_NONE)
++ return HISI_SAS_SATA_PROTOCOL_NONDATA;
++ return HISI_SAS_SATA_PROTOCOL_PIO;
++ }
++}
++EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
++
+ static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+ {
+ return device->port->ha->lldd_ha;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 2607aac00ac9..d9314c4eff0f 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -554,12 +554,6 @@ enum {
+ #define DIR_TO_DEVICE 2
+ #define DIR_RESERVED 3
+
+-#define SATA_PROTOCOL_NONDATA 0x1
+-#define SATA_PROTOCOL_PIO 0x2
+-#define SATA_PROTOCOL_DMA 0x4
+-#define SATA_PROTOCOL_FPDMA 0x8
+-#define SATA_PROTOCOL_ATAPI 0x10
+-
+ #define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \
+ err_phase == 0x4 || err_phase == 0x8 ||\
+ err_phase == 0x6 || err_phase == 0xa)
+@@ -2352,64 +2346,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ return sts;
+ }
+
+-static u8 get_ata_protocol(u8 cmd, int direction)
+-{
+- switch (cmd) {
+- case ATA_CMD_FPDMA_WRITE:
+- case ATA_CMD_FPDMA_READ:
+- case ATA_CMD_FPDMA_RECV:
+- case ATA_CMD_FPDMA_SEND:
+- case ATA_CMD_NCQ_NON_DATA:
+- return SATA_PROTOCOL_FPDMA;
+-
+- case ATA_CMD_DOWNLOAD_MICRO:
+- case ATA_CMD_ID_ATA:
+- case ATA_CMD_PMP_READ:
+- case ATA_CMD_READ_LOG_EXT:
+- case ATA_CMD_PIO_READ:
+- case ATA_CMD_PIO_READ_EXT:
+- case ATA_CMD_PMP_WRITE:
+- case ATA_CMD_WRITE_LOG_EXT:
+- case ATA_CMD_PIO_WRITE:
+- case ATA_CMD_PIO_WRITE_EXT:
+- return SATA_PROTOCOL_PIO;
+-
+- case ATA_CMD_DSM:
+- case ATA_CMD_DOWNLOAD_MICRO_DMA:
+- case ATA_CMD_PMP_READ_DMA:
+- case ATA_CMD_PMP_WRITE_DMA:
+- case ATA_CMD_READ:
+- case ATA_CMD_READ_EXT:
+- case ATA_CMD_READ_LOG_DMA_EXT:
+- case ATA_CMD_READ_STREAM_DMA_EXT:
+- case ATA_CMD_TRUSTED_RCV_DMA:
+- case ATA_CMD_TRUSTED_SND_DMA:
+- case ATA_CMD_WRITE:
+- case ATA_CMD_WRITE_EXT:
+- case ATA_CMD_WRITE_FUA_EXT:
+- case ATA_CMD_WRITE_QUEUED:
+- case ATA_CMD_WRITE_LOG_DMA_EXT:
+- case ATA_CMD_WRITE_STREAM_DMA_EXT:
+- return SATA_PROTOCOL_DMA;
+-
+- case ATA_CMD_CHK_POWER:
+- case ATA_CMD_DEV_RESET:
+- case ATA_CMD_EDD:
+- case ATA_CMD_FLUSH:
+- case ATA_CMD_FLUSH_EXT:
+- case ATA_CMD_VERIFY:
+- case ATA_CMD_VERIFY_EXT:
+- case ATA_CMD_SET_FEATURES:
+- case ATA_CMD_STANDBY:
+- case ATA_CMD_STANDBYNOW1:
+- return SATA_PROTOCOL_NONDATA;
+- default:
+- if (direction == DMA_NONE)
+- return SATA_PROTOCOL_NONDATA;
+- return SATA_PROTOCOL_PIO;
+- }
+-}
+-
+ static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag)
+ {
+ struct ata_queued_cmd *qc = task->uldd_task;
+@@ -2464,7 +2400,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ (task->ata_task.fis.control & ATA_SRST))
+ dw1 |= 1 << CMD_HDR_RESET_OFF;
+
+- dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir))
++ dw1 |= (hisi_sas_get_ata_protocol(
++ task->ata_task.fis.command, task->data_dir))
+ << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch b/patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch
new file mode 100644
index 0000000000..4ff6ed7bbe
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch
@@ -0,0 +1,95 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:16 +0800
+Subject: scsi: hisi_sas: relocate get_ncq_tag_v2_hw()
+Git-commit: 318913c63c5d435cba30c7f744bd0f24d7295516
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Relocate get_ncq_tag_v2_hw() to a common location, as future hw versions
+will require it. Also rename with "hisi_sas_" prefix for consistency.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 1 +
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++++++++++++++
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 16 +---------------
+ 3 files changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 1dcdf66906ac..19c6ffd6d4ff 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -366,6 +366,7 @@ extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
+ extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
+ extern void hisi_sas_sata_done(struct sas_task *task,
+ struct hisi_sas_slot *slot);
++extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag);
+ extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+ extern int hisi_sas_remove(struct platform_device *pdev);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index ab133d4dd827..f53a93b1f955 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -97,6 +97,21 @@ void hisi_sas_sata_done(struct sas_task *task,
+ }
+ EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
+
++int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag)
++{
++ struct ata_queued_cmd *qc = task->uldd_task;
++
++ if (qc) {
++ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
++ qc->tf.command == ATA_CMD_FPDMA_READ) {
++ *tag = qc->tag;
++ return 1;
++ }
++ }
++ return 0;
++}
++EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag);
++
+ static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+ {
+ return device->port->ha->lldd_ha;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index fdd7019ef299..9cc54357eeb0 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -2332,20 +2332,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ return sts;
+ }
+
+-static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag)
+-{
+- struct ata_queued_cmd *qc = task->uldd_task;
+-
+- if (qc) {
+- if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+- qc->tf.command == ATA_CMD_FPDMA_READ) {
+- *tag = qc->tag;
+- return 1;
+- }
+- }
+- return 0;
+-}
+-
+ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+ {
+@@ -2393,7 +2379,7 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ /* dw2 */
+- if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, &hdr_tag)) {
++ if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) {
+ task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+ dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
+ }
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch b/patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch
new file mode 100644
index 0000000000..3a6692cd86
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch
@@ -0,0 +1,105 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Wed, 14 Jun 2017 23:33:15 +0800
+Subject: scsi: hisi_sas: relocate sata_done_v2_hw()
+Git-commit: 759040770dbc7c8c53aa23552d2d955e80c91ce6
+Patch-mainline: v4.13-rc1
+References: bsc#1068693
+
+Relocate get_ata_protocol() to a common location, as future hw versions
+will require it. Also rename with "hisi_sas_" prefix for consistency.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 2 ++
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++++++++++++++
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 18 ++----------------
+ 3 files changed, 19 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index a50c69989352..1dcdf66906ac 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -364,6 +364,8 @@ union hisi_sas_command_table {
+
+ extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
+ extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
++extern void hisi_sas_sata_done(struct sas_task *task,
++ struct hisi_sas_slot *slot);
+ extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+ extern int hisi_sas_remove(struct platform_device *pdev);
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 5b51d9af2013..ab133d4dd827 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -82,6 +82,21 @@ u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
+ }
+ EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
+
++void hisi_sas_sata_done(struct sas_task *task,
++ struct hisi_sas_slot *slot)
++{
++ struct task_status_struct *ts = &task->task_status;
++ struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
++ struct dev_to_host_fis *d2h = slot->status_buffer +
++ sizeof(struct hisi_sas_err_record);
++
++ resp->frame_len = sizeof(struct dev_to_host_fis);
++ memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
++
++ ts->buf_valid_size = sizeof(*resp);
++}
++EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
++
+ static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+ {
+ return device->port->ha->lldd_ha;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index d9314c4eff0f..fdd7019ef299 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -1683,20 +1683,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+ return 0;
+ }
+
+-static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
+- struct hisi_sas_slot *slot)
+-{
+- struct task_status_struct *ts = &task->task_status;
+- struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+- struct dev_to_host_fis *d2h = slot->status_buffer +
+- sizeof(struct hisi_sas_err_record);
+-
+- resp->frame_len = sizeof(struct dev_to_host_fis);
+- memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+-
+- ts->buf_valid_size = sizeof(*resp);
+-}
+-
+ #define TRANS_TX_ERR 0
+ #define TRANS_RX_ERR 1
+ #define DMA_TX_ERR 2
+@@ -2189,7 +2175,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ break;
+ }
+ }
+- sata_done_v2_hw(hisi_hba, task, slot);
++ hisi_sas_sata_done(task, slot);
+ }
+ break;
+ default:
+@@ -2317,7 +2303,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ ts->stat = SAM_STAT_GOOD;
+- sata_done_v2_hw(hisi_hba, task, slot);
++ hisi_sas_sata_done(task, slot);
+ break;
+ }
+ default:
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch b/patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch
new file mode 100644
index 0000000000..a141dcca66
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch
@@ -0,0 +1,68 @@
+From: John Garry <john.garry@huawei.com>
+Date: Fri, 11 Aug 2017 00:09:44 +0800
+Subject: scsi: hisi_sas: remove driver versioning
+Git-commit: 30b67de31bc6c0cdc80c03358dc94b44cc178ba9
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+The driver version is not updated with changes to the driver, so it has
+no value, so just get rid of it.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 2 --
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 -
+ 3 files changed, 6 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index 4c393cd8ee81..07f4a4cfbec1 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -26,8 +26,6 @@
+ #include <scsi/sas_ata.h>
+ #include <scsi/libsas.h>
+
+-#define DRV_VERSION "v1.6"
+-
+ #define HISI_SAS_MAX_PHYS 9
+ #define HISI_SAS_MAX_QUEUES 32
+ #define HISI_SAS_QUEUE_SLOTS 512
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 9427835b5021..bdef111434b8 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -2013,8 +2013,6 @@ EXPORT_SYMBOL_GPL(hisi_sas_remove);
+
+ static __init int hisi_sas_init(void)
+ {
+- pr_info("hisi_sas: driver version %s\n", DRV_VERSION);
+-
+ hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
+ if (!hisi_sas_stt)
+ return -ENOMEM;
+@@ -2030,7 +2028,6 @@ static __exit void hisi_sas_exit(void)
+ module_init(hisi_sas_init);
+ module_exit(hisi_sas_exit);
+
+-MODULE_VERSION(DRV_VERSION);
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+ MODULE_DESCRIPTION("HISILICON SAS controller driver");
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index a20e354383f0..2e5fa9717be8 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -2005,7 +2005,6 @@ static struct pci_driver sas_v3_pci_driver = {
+
+ module_pci_driver(sas_v3_pci_driver);
+
+-MODULE_VERSION(DRV_VERSION);
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+ MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch b/patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch
new file mode 100644
index 0000000000..a8c4a4e405
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch
@@ -0,0 +1,62 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:31 +0800
+Subject: scsi: hisi_sas: remove repeated device config in v2 hw
+Git-commit: cef4e1ab7a16f64ee75172ce28832e7f6abaeace
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+This patch removes some repeated configurations:
+
+(1) The device id of the device is already set in the alloc function, so
+ we don't need to modify in free device function.
+
+(2) Field dev_type and dev_status are configured in hisi_sas_dev_gone(),
+ so there is no need for repeated config in free_device_v3_hw.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ---
+ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 --
+ 2 files changed, 5 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index aaa7296421a2..81ad6cd17f94 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -716,7 +716,6 @@ static void hisi_sas_dev_gone(struct domain_device *device)
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = hisi_hba->dev;
+- int dev_id = sas_dev->device_id;
+
+ dev_info(dev, "found dev[%d:%x] is gone\n",
+ sas_dev->device_id, sas_dev->dev_type);
+@@ -729,9 +728,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
+ hisi_hba->hw->free_device(hisi_hba, sas_dev);
+ device->lldd_dev = NULL;
+ memset(sas_dev, 0, sizeof(*sas_dev));
+- sas_dev->device_id = dev_id;
+ sas_dev->dev_type = SAS_PHY_UNUSED;
+- sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ }
+
+ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+index 83d2dca1c650..dc5c5515d5c3 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+@@ -578,8 +578,6 @@ static void free_device_v3_hw(struct hisi_hba *hisi_hba,
+ memset(itct, 0, sizeof(struct hisi_sas_itct));
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+- hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED;
+- hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL;
+
+ /* clear the itct */
+ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch b/patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch
new file mode 100644
index 0000000000..38899d756a
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch
@@ -0,0 +1,123 @@
+From: Xiang Chen <chenxiang66@hisilicon.com>
+Date: Fri, 11 Aug 2017 00:09:33 +0800
+Subject: scsi: hisi_sas: service interrupt ITCT_CLR interrupt in v2 hw
+Git-commit: 640acc9a9693e729b7936fb4801f2dd59041a141
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+This patch is a fix related to freeing a device in v2 hw driver.
+
+Before, we polled to ITCT CLR interrupt to check if a device is free.
+
+This was error prone, as if the interrupt doesn't occur in 10us, we miss
+processing it.
+
+To avoid this situation, service this interrupt and sync the event with
+a completion.
+
+Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 1 +
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 40 ++++++++++++++++------------------
+ 2 files changed, 20 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index ad6b2d18047b..23a22dcba154 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -141,6 +141,7 @@ struct hisi_sas_dq {
+ struct hisi_sas_device {
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
++ struct completion *completion;
+ struct hisi_sas_dq *dq;
+ struct list_head list;
+ u64 attached_phy;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 9eea0b4e0434..0e3634ec1225 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -974,12 +974,14 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
+ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+ {
++ DECLARE_COMPLETION_ONSTACK(completion);
+ u64 dev_id = sas_dev->device_id;
+- struct device *dev = hisi_hba->dev;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ int i;
+
++ sas_dev->completion = &completion;
++
+ /* SoC bug workaround */
+ if (dev_is_sata(sas_dev->sas_device))
+ clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+@@ -989,28 +991,12 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+
+- /* clear the itct int*/
+ for (i = 0; i < 2; i++) {
+- /* clear the itct table*/
+- reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
+- reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
++ reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
+ hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
++ wait_for_completion(sas_dev->completion);
+
+- udelay(10);
+- reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+- if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
+- dev_dbg(dev, "got clear ITCT done interrupt\n");
+-
+- /* invalid the itct state*/
+- memset(itct, 0, sizeof(struct hisi_sas_itct));
+- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+- ENT_INT_SRC3_ITC_INT_MSK);
+-
+- /* clear the itct */
+- hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+- dev_dbg(dev, "clear ITCT ok\n");
+- break;
+- }
++ memset(itct, 0, sizeof(struct hisi_sas_itct));
+ }
+ }
+
+@@ -1191,7 +1177,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
+- hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffffffe);
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffe20fe);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
+@@ -3092,8 +3078,20 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
++
++ if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) {
++ u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
++ u32 dev_id = reg_val & ITCT_DEV_MSK;
++ struct hisi_sas_device *sas_dev =
++ &hisi_hba->devices[dev_id];
++
++ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
++ dev_dbg(dev, "clear ITCT ok\n");
++ complete(sas_dev->completion);
++ }
+ }
+
++ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, irq_value);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk);
+
+ return IRQ_HANDLED;
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch b/patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch
new file mode 100644
index 0000000000..ebeb670a16
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch
@@ -0,0 +1,41 @@
+From: Xiaofei Tan <tanxiaofei@huawei.com>
+Date: Fri, 11 Aug 2017 00:09:34 +0800
+Subject: scsi: hisi_sas: support zone management commands
+Git-commit: c3fe8a2bbbc22bd4945ea69ab5a29913baeb35e4
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+Add two ATA commands, ATA_CMD_ZAC_MGMT_IN and ATA_CMD_ZAC_MGMT_OUT in
+hisi_sas_get_ata_protocol(), to support SATA SMR disk.
+
+Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index 81ad6cd17f94..86868ec66178 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -61,6 +61,7 @@ u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
+ case ATA_CMD_WRITE_QUEUED:
+ case ATA_CMD_WRITE_LOG_DMA_EXT:
+ case ATA_CMD_WRITE_STREAM_DMA_EXT:
++ case ATA_CMD_ZAC_MGMT_IN:
+ return HISI_SAS_SATA_PROTOCOL_DMA;
+
+ case ATA_CMD_CHK_POWER:
+@@ -73,6 +74,7 @@ u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
+ case ATA_CMD_SET_FEATURES:
+ case ATA_CMD_STANDBY:
+ case ATA_CMD_STANDBYNOW1:
++ case ATA_CMD_ZAC_MGMT_OUT:
+ return HISI_SAS_SATA_PROTOCOL_NONDATA;
+ default:
+ if (direction == DMA_NONE)
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch b/patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch
new file mode 100644
index 0000000000..90878fa2a2
--- /dev/null
+++ b/patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch
@@ -0,0 +1,436 @@
+From: John Garry <john.garry@huawei.com>
+Date: Fri, 11 Aug 2017 00:09:30 +0800
+Subject: scsi: hisi_sas: use array for v2 hw ECC errors
+Git-commit: 2b3833510d7f85120ba4dbaf2d5575415f09d27b
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+The code to print ECC errors in v2 hw driver is very repetitive. This
+patch condensed the code by looping an array of errors.
+
+Signed-off-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Shiju Jose <shiju.jose@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/hisi_sas/hisi_sas.h | 8 +
+ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 368 +++++++++++++++++----------------
+ 2 files changed, 197 insertions(+), 179 deletions(-)
+
+diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
+index ef2238c6e4da..ad6b2d18047b 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas.h
++++ b/drivers/scsi/hisi_sas/hisi_sas.h
+@@ -91,6 +91,14 @@ enum hisi_sas_dev_type {
+ HISI_SAS_DEV_TYPE_SATA,
+ };
+
++struct hisi_sas_hw_error {
++ u32 irq_msk;
++ u32 msk;
++ int shift;
++ const char *msg;
++ int reg;
++};
++
+ struct hisi_sas_phy {
+ struct hisi_hba *hisi_hba;
+ struct hisi_sas_port *port;
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+index 41e8033ad1c8..bcbc16e4cec0 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+@@ -401,6 +401,172 @@ struct hisi_sas_err_record_v2 {
+ __le32 dma_rx_err_type;
+ };
+
++static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
++ .msk = HGC_DQE_ECC_1B_ADDR_MSK,
++ .shift = HGC_DQE_ECC_1B_ADDR_OFF,
++ .msg = "hgc_dqe_acc1b_intr found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_DQE_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
++ .msk = HGC_IOST_ECC_1B_ADDR_MSK,
++ .shift = HGC_IOST_ECC_1B_ADDR_OFF,
++ .msg = "hgc_iost_acc1b_intr found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_IOST_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
++ .msk = HGC_ITCT_ECC_1B_ADDR_MSK,
++ .shift = HGC_ITCT_ECC_1B_ADDR_OFF,
++ .msg = "hgc_itct_acc1b_intr found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_ITCT_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
++ .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
++ .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
++ .msg = "hgc_iostl_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_LM_DFX_STATUS2,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
++ .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
++ .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
++ .msg = "hgc_itctl_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_LM_DFX_STATUS2,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
++ .msk = HGC_CQE_ECC_1B_ADDR_MSK,
++ .shift = HGC_CQE_ECC_1B_ADDR_OFF,
++ .msg = "hgc_cqe_acc1b_intr found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_CQE_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
++ .msg = "rxm_mem0_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
++ .msg = "rxm_mem1_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
++ .msg = "rxm_mem2_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
++ .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
++ .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
++ .msg = "rxm_mem3_acc1b_intr found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS15,
++ },
++};
++
++static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
++ .msk = HGC_DQE_ECC_MB_ADDR_MSK,
++ .shift = HGC_DQE_ECC_MB_ADDR_OFF,
++ .msg = "hgc_dqe_accbad_intr (0x%x) found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_DQE_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
++ .msk = HGC_IOST_ECC_MB_ADDR_MSK,
++ .shift = HGC_IOST_ECC_MB_ADDR_OFF,
++ .msg = "hgc_iost_accbad_intr (0x%x) found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_IOST_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
++ .msk = HGC_ITCT_ECC_MB_ADDR_MSK,
++ .shift = HGC_ITCT_ECC_MB_ADDR_OFF,
++ .msg = "hgc_itct_accbad_intr (0x%x) found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_ITCT_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
++ .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
++ .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
++ .msg = "hgc_iostl_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_LM_DFX_STATUS2,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
++ .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
++ .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
++ .msg = "hgc_itctl_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_LM_DFX_STATUS2,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
++ .msk = HGC_CQE_ECC_MB_ADDR_MSK,
++ .shift = HGC_CQE_ECC_MB_ADDR_OFF,
++ .msg = "hgc_cqe_accbad_intr (0x%x) found: \
++ Ram address is 0x%08X\n",
++ .reg = HGC_CQE_ECC_ADDR,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
++ .msg = "rxm_mem0_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
++ .msg = "rxm_mem1_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
++ .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
++ .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
++ .msg = "rxm_mem2_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS14,
++ },
++ {
++ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
++ .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
++ .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
++ .msg = "rxm_mem3_accbad_intr (0x%x) found: \
++ memory address is 0x%08X\n",
++ .reg = HGC_RXM_DFX_STATUS15,
++ },
++};
++
+ enum {
+ HISI_SAS_PHY_PHY_UPDOWN,
+ HISI_SAS_PHY_CHNL_INT,
+@@ -2762,194 +2928,38 @@ static void
+ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
+ {
+ struct device *dev = hisi_hba->dev;
+- u32 reg_val;
+-
+- if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
+- dev_warn(dev, "hgc_dqe_acc1b_intr found: \
+- Ram address is 0x%08X\n",
+- (reg_val & HGC_DQE_ECC_1B_ADDR_MSK) >>
+- HGC_DQE_ECC_1B_ADDR_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR);
+- dev_warn(dev, "hgc_iost_acc1b_intr found: \
+- Ram address is 0x%08X\n",
+- (reg_val & HGC_IOST_ECC_1B_ADDR_MSK) >>
+- HGC_IOST_ECC_1B_ADDR_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR);
+- dev_warn(dev, "hgc_itct_acc1b_intr found: \
+- Ram address is 0x%08X\n",
+- (reg_val & HGC_ITCT_ECC_1B_ADDR_MSK) >>
+- HGC_ITCT_ECC_1B_ADDR_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
+- dev_warn(dev, "hgc_iostl_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >>
+- HGC_LM_DFX_STATUS2_IOSTLIST_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
+- dev_warn(dev, "hgc_itctl_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >>
+- HGC_LM_DFX_STATUS2_ITCTLIST_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR);
+- dev_warn(dev, "hgc_cqe_acc1b_intr found: \
+- Ram address is 0x%08X\n",
+- (reg_val & HGC_CQE_ECC_1B_ADDR_MSK) >>
+- HGC_CQE_ECC_1B_ADDR_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem0_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM0_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem1_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM1_OFF);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem2_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM2_OFF);
+- }
++ const struct hisi_sas_hw_error *ecc_error;
++ u32 val;
++ int i;
+
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15);
+- dev_warn(dev, "rxm_mem3_acc1b_intr found: \
+- memory address is 0x%08X\n",
+- (reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >>
+- HGC_RXM_DFX_STATUS15_MEM3_OFF);
++ for (i = 0; i < ARRAY_SIZE(one_bit_ecc_errors); i++) {
++ ecc_error = &one_bit_ecc_errors[i];
++ if (irq_value & ecc_error->irq_msk) {
++ val = hisi_sas_read32(hisi_hba, ecc_error->reg);
++ val &= ecc_error->msk;
++ val >>= ecc_error->shift;
++ dev_warn(dev, ecc_error->msg, val);
++ }
+ }
+-
+ }
+
+ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
+ u32 irq_value)
+ {
+- u32 reg_val;
+ struct device *dev = hisi_hba->dev;
++ const struct hisi_sas_hw_error *ecc_error;
++ u32 val;
++ int i;
+
+- if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
+- dev_warn(dev, "hgc_dqe_accbad_intr (0x%x) found: \
+- Ram address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_DQE_ECC_MB_ADDR_MSK) >>
+- HGC_DQE_ECC_MB_ADDR_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR);
+- dev_warn(dev, "hgc_iost_accbad_intr (0x%x) found: \
+- Ram address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_IOST_ECC_MB_ADDR_MSK) >>
+- HGC_IOST_ECC_MB_ADDR_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR);
+- dev_warn(dev,"hgc_itct_accbad_intr (0x%x) found: \
+- Ram address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_ITCT_ECC_MB_ADDR_MSK) >>
+- HGC_ITCT_ECC_MB_ADDR_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
+- dev_warn(dev, "hgc_iostl_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >>
+- HGC_LM_DFX_STATUS2_IOSTLIST_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
+- dev_warn(dev, "hgc_itctl_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >>
+- HGC_LM_DFX_STATUS2_ITCTLIST_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR);
+- dev_warn(dev, "hgc_cqe_accbad_intr (0x%x) found: \
+- Ram address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_CQE_ECC_MB_ADDR_MSK) >>
+- HGC_CQE_ECC_MB_ADDR_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem0_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM0_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem1_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM1_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
+- dev_warn(dev, "rxm_mem2_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >>
+- HGC_RXM_DFX_STATUS14_MEM2_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+- }
+-
+- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF)) {
+- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15);
+- dev_warn(dev, "rxm_mem3_accbad_intr (0x%x) found: \
+- memory address is 0x%08X\n",
+- irq_value,
+- (reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >>
+- HGC_RXM_DFX_STATUS15_MEM3_OFF);
+- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
++ for (i = 0; i < ARRAY_SIZE(multi_bit_ecc_errors); i++) {
++ ecc_error = &multi_bit_ecc_errors[i];
++ if (irq_value & ecc_error->irq_msk) {
++ val = hisi_sas_read32(hisi_hba, ecc_error->reg);
++ val &= ecc_error->msk;
++ val >>= ecc_error->shift;
++ dev_warn(dev, ecc_error->msg, irq_value, val);
++ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
++ }
+ }
+
+ return;
+--
+2.14.2
+
diff --git a/patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch b/patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch
new file mode 100644
index 0000000000..834cea8e6d
--- /dev/null
+++ b/patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch
@@ -0,0 +1,148 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 25 Aug 2017 13:57:02 +0200
+Subject: scsi: libsas: move bus_reset_handler() to target_reset_handler()
+Git-commit: cc199e78460565eeab0399875dbf9da8e2901c42
+Patch-mainline: v4.14-rc1
+References: bsc#1068693
+
+The bus reset handler is calling I_T Nexus reset, which logically is a
+target reset as it need to specify both the initiator and the target.
+So move it to target reset.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ drivers/scsi/aic94xx/aic94xx_init.c | 2 +-
+ drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +-
+ drivers/scsi/isci/init.c | 2 +-
+ drivers/scsi/libsas/sas_scsi_host.c | 12 ++++++------
+ drivers/scsi/mvsas/mv_init.c | 2 +-
+ drivers/scsi/pm8001/pm8001_init.c | 2 +-
+ include/scsi/libsas.h | 2 +-
+ 7 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
+index a240feee16e5..6c838865ac5a 100644
+--- a/drivers/scsi/aic94xx/aic94xx_init.c
++++ b/drivers/scsi/aic94xx/aic94xx_init.c
+@@ -70,7 +70,7 @@ static struct scsi_host_template aic94xx_sht = {
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+- .eh_bus_reset_handler = sas_eh_bus_reset_handler,
++ .eh_target_reset_handler = sas_eh_target_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ .track_queue_depth = 1,
+diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
+index bdef111434b8..16664f2e15fb 100644
+--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
+@@ -1562,7 +1562,7 @@ static struct scsi_host_template _hisi_sas_sht = {
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+- .eh_bus_reset_handler = sas_eh_bus_reset_handler,
++ .eh_target_reset_handler = sas_eh_target_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ };
+diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
+index 45371179ab87..922e3e56c90d 100644
+--- a/drivers/scsi/isci/init.c
++++ b/drivers/scsi/isci/init.c
+@@ -166,7 +166,7 @@ static struct scsi_host_template isci_sht = {
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_abort_handler = sas_eh_abort_handler,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+- .eh_bus_reset_handler = sas_eh_bus_reset_handler,
++ .eh_target_reset_handler = sas_eh_target_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ .shost_attrs = isci_host_attrs,
+diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
+index fc90b8c65860..ea8ad06ff582 100644
+--- a/drivers/scsi/libsas/sas_scsi_host.c
++++ b/drivers/scsi/libsas/sas_scsi_host.c
+@@ -526,7 +526,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
+ return FAILED;
+ }
+
+-int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
++int sas_eh_target_reset_handler(struct scsi_cmnd *cmd)
+ {
+ int res;
+ struct Scsi_Host *host = cmd->device->host;
+@@ -554,15 +554,15 @@ static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
+ struct Scsi_Host *shost = cmd->device->host;
+
+ if (!shost->hostt->eh_device_reset_handler)
+- goto try_bus_reset;
++ goto try_target_reset;
+
+ res = shost->hostt->eh_device_reset_handler(cmd);
+ if (res == SUCCESS)
+ return res;
+
+-try_bus_reset:
+- if (shost->hostt->eh_bus_reset_handler)
+- return shost->hostt->eh_bus_reset_handler(cmd);
++try_target_reset:
++ if (shost->hostt->eh_target_reset_handler)
++ return shost->hostt->eh_target_reset_handler(cmd);
+
+ return FAILED;
+ }
+@@ -993,6 +993,6 @@ EXPORT_SYMBOL_GPL(sas_bios_param);
+ EXPORT_SYMBOL_GPL(sas_task_abort);
+ EXPORT_SYMBOL_GPL(sas_phy_reset);
+ EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
+-EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
++EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler);
+ EXPORT_SYMBOL_GPL(sas_target_destroy);
+ EXPORT_SYMBOL_GPL(sas_ioctl);
+diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
+index f0a096a1e276..718c88de328b 100644
+--- a/drivers/scsi/mvsas/mv_init.c
++++ b/drivers/scsi/mvsas/mv_init.c
+@@ -61,7 +61,7 @@ static struct scsi_host_template mvs_sht = {
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+- .eh_bus_reset_handler = sas_eh_bus_reset_handler,
++ .eh_target_reset_handler = sas_eh_target_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ .shost_attrs = mvst_host_attrs,
+diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
+index 2908881bad51..0e013f76b582 100644
+--- a/drivers/scsi/pm8001/pm8001_init.c
++++ b/drivers/scsi/pm8001/pm8001_init.c
+@@ -86,7 +86,7 @@ static struct scsi_host_template pm8001_sht = {
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+- .eh_bus_reset_handler = sas_eh_bus_reset_handler,
++ .eh_target_reset_handler = sas_eh_target_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ .shost_attrs = pm8001_host_attrs,
+diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
+index cfaeed256ab2..e7c012ce5ecd 100644
+--- a/include/scsi/libsas.h
++++ b/include/scsi/libsas.h
+@@ -714,7 +714,7 @@ void sas_init_dev(struct domain_device *);
+ void sas_task_abort(struct sas_task *);
+ int sas_eh_abort_handler(struct scsi_cmnd *cmd);
+ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
+-int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
++int sas_eh_target_reset_handler(struct scsi_cmnd *cmd);
+
+ extern void sas_target_destroy(struct scsi_target *);
+ extern int sas_slave_alloc(struct scsi_device *);
+--
+2.14.2
+
diff --git a/series.conf b/series.conf
index 0ca4d4cab2..ee51f1b3fe 100644
--- a/series.conf
+++ b/series.conf
@@ -3463,6 +3463,8 @@
patches.drivers/qed-Add-iWARP-protocol-support-in-context-allocation.patch
patches.drivers/qed-Add-iWARP-support-for-physical-queue-allocation.patch
patches.drivers/net-mlx5-fix-memcpy-limit.patch
+ patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch
+ patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch
patches.drivers/bpf-export-whether-tail-call-has-jited-owner.patch
patches.drivers/ctcm_fsms-Convert-skb-user-accesses-to-refcount_t.patch
patches.drivers/net-mlxfw-Properly-handle-dependancy-with-non-loadab.patch
@@ -3611,6 +3613,7 @@
patches.drivers/scsi-csiostor-add-support-for-Chelsio-T6-adapters.patch
patches.drivers/scsi-csiostor-Avoid-content-leaks-and-casts.patch
patches.drivers/scsi-smartpqi-mark-PM-functions-as-__maybe_unused.patch
+ patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch
patches.drivers/0001-scsi-qla2xxx-Remove-an-unused-structure-member.patch
patches.drivers/scsi-lpfc-fix-spelling-mistake-entrys-entries.patch
patches.drivers/scsi-fcoe-Fix-few-small-typos-in-fcoe.c.patch
@@ -3685,6 +3688,28 @@
patches.drivers/scsi-lpfc-Fix-defects-reported-by-Coverity-Scan.patch
patches.drivers/scsi-lpfc-Add-auto-EQ-delay-logic.patch
patches.drivers/scsi-lpfc-update-to-revision-to-11.4.0.0.patch
+ patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch
+ patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch
+ patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch
+ patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch
+ patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch
+ patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch
+ patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch
+ patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch
+ patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch
+ patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch
+ patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch
+ patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch
+ patches.drivers/0013-scsi-hisi_sas-add-phy-up-down-bcast-and-channel-ISR.patch
+ patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch
+ patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch
+ patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch
+ patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch
+ patches.drivers/0018-scsi-hisi_sas-add-v3-code-for-itct-setup-and-free.patch
+ patches.drivers/0019-scsi-hisi_sas-add-v3-code-to-send-internal-abort-com.patch
+ patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch
+ patches.drivers/0021-scsi-hisi_sas-add-v3-code-to-fill-some-more-hw-funct.patch
+ patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch
patches.drivers/scsi-lpfc-Fix-system-panic-when-express-lane-enabled.patch
patches.drivers/scsi-lpfc-Fix-nvme_info-sysfs-output-to-be-consisten.patch
patches.drivers/scsi-lpfc-Vport-creation-is-failing-with-Link-Down-e.patch
@@ -3708,6 +3733,7 @@
patches.drivers/scsi-cxgb4i-assign-rxqs-in-round-robin-mode
patches.drivers/scsi-bnx2i-missing-error-code-in-bnx2i_ep_connect
patches.drivers/0021-scsi-aacraid-Don-t-copy-uninitialized-stack-memory-t.patch
+ patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch
patches.drivers/scsi-qedi-Remove-comparison-of-u16-idx-with-zero.patch
patches.drivers/scsi-cxlflash-01-Combine-the-send-queue-locks.patch
patches.drivers/scsi-cxlflash-02-Update-cxlflash_afu_sync-to-return-err.patch
@@ -3764,6 +3790,7 @@
patches.drivers/scsi-cxlflash-18-Avoid-double-free-of-character-device.patch
patches.drivers/scsi-cxlflash-19-Update-send_tmf-parameters.patch
patches.drivers/scsi-cxlflash-20-Update-debug-prints-in-reset-handlers.patch
+ patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch
patches.drivers/scsi-lpfc-spin_lock_irq-is-not-nestable.patch
patches.drivers/scsi-lpfc-don-t-double-count-abort-errors.patch
patches.drivers/0042-scsi-qla2xxx-fix-a-bunch-of-typos-and-spelling-mista.patch
@@ -3799,6 +3826,8 @@
patches.drivers/IB-core-Fix-uninitialized-variable-use-in-check_qp_p.patch
patches.drivers/IB-core-Fix-static-analysis-warning-in-ib_policy_cha.patch
patches.drivers/nfp-flower-add-missing-clean-up-call-to-avoid-memory.patch
+ patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch
+ patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch
patches.suse/0001-lib-raid6-Add-log-of-2-table-for-RAID6-HW-requiring-.patch
patches.suse/0028-md-raid10-fix-FailFast-test-for-wrong-device.patch
patches.suse/0029-md-raid1-remove-unused-bio-in-sync_request_write.patch
@@ -3858,6 +3887,7 @@
patches.drivers/cisco-enic-Fic-an-error-handling-path-in-vnic_dev_in.patch
patches.drivers/qed-Fix-printk-option-passed-when-printing-ipv6-addr.patch
patches.drivers/nfp-freeing-the-wrong-variable.patch
+ patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch
patches.drivers/rtc-rtc-nuc900-fix-loop-timeout-test.patch
patches.drivers/IB-rxe-do-not-copy-extra-stack-memory-to-skb.patch
patches.drivers/drivers-s390-move-static-and-inline-before-return-ty.patch
@@ -3930,6 +3960,7 @@
patches.drivers/scsi-qedi-fix-another-spelling-mistake-alloction-all.patch
patches.drivers/scsi-qedf-fix-spelling-mistake-offlading-offloading.patch
patches.drivers/0046-scsi-qla2xxx-Off-by-one-in-qlt_ctio_to_cmd.patch
+ patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch
patches.drivers/scsi-libfc-pass-an-error-pointer-to-fc_disc_error.patch
patches.drivers/IB-hfi1-Ensure-dd-gi_mask-can-not-be-overflowed.patch
patches.drivers/RDMA-core-Document-confusing-code.patch
@@ -3954,6 +3985,7 @@
patches.drivers/net-broadcom-bnx2x-make-a-couple-of-const-arrays-sta.patch
patches.drivers/cxgb4-add-new-T5-pci-device-id-s.patch
patches.drivers/netpoll-shut-up-a-kernel-warning-on-refcount.patch
+ patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch
patches.drivers/cxgb4-ptp_clock_register-returns-error-pointers.patch
patches.drivers/net-bridge-fix-dest-lookup-when-vlan-proto-doesn-t-m.patch
patches.drivers/bnx2x-fix-format-overflow-warning.patch
@@ -4130,6 +4162,7 @@
patches.drivers/nvmet-fc-eliminate-incorrect-static-markers-on-local.patch
patches.drivers/nvme-fabrics-fix-reporting-of-unrecognized-options.patch
patches.drivers/nvme-pci-set-cqe_seen-on-polled-completions.patch
+ patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch
patches.drivers/net-sched-fix-p_filter_chain-check-in-tcf_chain_flus.patch
patches.drivers/netxen-fix-incorrect-loop-counter-decrement.patch
patches.drivers/0005-PCI-Allow-PCI-express-root-ports-to-find-themselves.patch
@@ -4536,6 +4569,7 @@
patches.drivers/qlcnic-remove-unnecessary-static-in-qlcnic_dump_fw.patch
patches.drivers/liquidio-lio_vf_main-remove-unnecessary-static-in-se.patch
patches.drivers/liquidio-lio_main-remove-unnecessary-static-in-setup.patch
+ patches.drivers/hns-remove-useless-void-cast.patch
patches.drivers/cxgb4-Update-register-ranges-of-T4-T5-T6-adapters.patch
patches.drivers/cxgb4-display-serial-config-and-vpd-versions.patch
patches.drivers/liquidio-fix-implicit-irq-include-causing-build-fail.patch
@@ -4602,11 +4636,13 @@
patches.fixes/tcp-remove-unused-mib-counters.patch
patches.fixes/tcp-tcp_data_queue-cleanup.patch
patches.drivers/liquidio-set-sriov_totalvfs-correctly.patch
+ patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch
patches.drivers/qlcnic-add-const-to-bin_attribute-structure.patch
patches.drivers/ibmvnic-106-Implement-per-queue-statistics-reporting.patch
patches.drivers/ibmvnic-107-Convert-vnic-server-reported-statistics-to-cpu-endian.patch
patches.drivers/ibmvnic-108-Implement-.get_ringparam.patch
patches.drivers/ibmvnic-109-Implement-.get_channels.patch
+ patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch
patches.drivers/net-sched-change-names-of-action-number-helpers-to-b.patch
patches.drivers/liquidio-add-missing-strings-in-oct_dev_state_str-ar.patch
patches.drivers/liquidio-moved-console_bitmask-module-param-to-lio_m.patch
@@ -4998,6 +5034,17 @@
patches.drivers/scsi-smartpqi-update-kexec-and-power-down-support.patch
patches.drivers/scsi-smartpqi-add-in-new-controller-ids.patch
patches.drivers/scsi-smartpqi-change-driver-version-to-1.1.2-125.patch
+ patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch
+ patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch
+ patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch
+ patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch
+ patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch
+ patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch
+ patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch
+ patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch
+ patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch
+ patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch
+ patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch
patches.drivers/scsi-qedi-Limit-number-for-CQ-queues.patch
patches.fixes/scsi-scsi_lib-rework-scsi_internal_device_unblock_no.patch
patches.fixes/scsi-make-state-device-attribute-pollable.patch
@@ -5088,6 +5135,7 @@
patches.drivers/scsi-lpfc-Add-Buffer-to-Buffer-credit-recovery-suppo.patch
patches.drivers/scsi-lpfc-fix-integer-constant-too-large-error-on-32.patch
patches.drivers/scsi-lpfc-lpfc-version-bump-11.4.0.3.patch
+ patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch
patches.drivers/scsi-qedf-drop-bus-reset-handler.patch
patches.drivers/scsi-megaraid_mbox-drop-duplicate-bus-reset-and-devi.patch
patches.fixes/scsi-ses-Fix-racy-cleanup-of-sys-in-remove_dev.patch
@@ -5366,6 +5414,7 @@
patches.drivers/nvme-Fix-setting-logical-block-format-when-revalidat.patch
patches.fixes/keys-return-full-count-in-keyring_read-if-buffer-is-too-small
patches.drivers/net-mlx5e-core-en_fs-fix-pointer-dereference-after-f.patch
+ patches.drivers/net-hns-set-correct-return-value.patch
patches.drivers/net-usb-asix-fill-null-ptr-deref-in-asix_suspend.patch
patches.drivers/net-mlx5-Loop-over-temp-list-to-release-delay-events.patch
patches.drivers/net-mlx5-Cancel-health-poll-before-sending-panic-tea.patch
diff --git a/supported.conf b/supported.conf
index e5981081e9..8671a2c9a6 100644
--- a/supported.conf
+++ b/supported.conf
@@ -1754,6 +1754,7 @@
drivers/scsi/hisi_sas/hisi_sas_main
drivers/scsi/hisi_sas/hisi_sas_v1_hw
drivers/scsi/hsis_sas/hisi_sas_v2_hw
+- drivers/scsi/hsis_sas/hisi_sas_v3_hw
drivers/scsi/hpsa # HP Smart Array bsc#555855 fate#307153
drivers/scsi/hptiop # fate#303913
+external +base drivers/scsi/hv_storvsc