diff --git a/config/arm64/default b/config/arm64/default index ef66195..8d68ac2 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 0000000..c399d9e --- /dev/null +++ b/patches.drivers/0009-scsi-hisi_sas-add-skeleton-v3-hw-driver.patch @@ -0,0 +1,114 @@ +From: John Garry +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 "); ++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 0000000..8e2ffc0 --- /dev/null +++ b/patches.drivers/0010-scsi-hisi_sas-add-initialisation-for-v3-pci-based-co.patch @@ -0,0 +1,300 @@ +From: John Garry +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..29744b3 --- /dev/null +++ b/patches.drivers/0011-scsi-hisi_sas-add-v3-hw-init.patch @@ -0,0 +1,316 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..8d3bbb8 --- /dev/null +++ b/patches.drivers/0012-scsi-hisi_sas-add-v3-hw-PHY-init.patch @@ -0,0 +1,229 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..474fa17 --- /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 +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..b46561f --- /dev/null +++ b/patches.drivers/0014-scsi-hisi_sas-add-v3-cq-interrupt-handler.patch @@ -0,0 +1,413 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..d127a70 --- /dev/null +++ b/patches.drivers/0015-scsi-hisi_sas-add-v3-code-to-send-SSP-frame.patch @@ -0,0 +1,267 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..7273e4f --- /dev/null +++ b/patches.drivers/0016-scsi-hisi_sas-add-v3-code-to-send-SMP-frame.patch @@ -0,0 +1,119 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..5fdaed5 --- /dev/null +++ b/patches.drivers/0017-scsi-hisi_sas-add-v3-code-to-send-ATA-frame.patch @@ -0,0 +1,167 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..b95a8cd --- /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 +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..9b9faf5 --- /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 +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..b0a41bc --- /dev/null +++ b/patches.drivers/0020-scsi-hisi_sas-add-get_wideport_bitmap_v3_hw.patch @@ -0,0 +1,51 @@ +From: Xiang Chen +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..fe015e6 --- /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 +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..495327d --- /dev/null +++ b/patches.drivers/0022-scsi-hisi_sas-modify-internal-abort-dev-flow-for-v3-.patch @@ -0,0 +1,143 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..943930f --- /dev/null +++ b/patches.drivers/clocksource-drivers-arm_arch_timer-Avoid-infinite-re.patch @@ -0,0 +1,62 @@ +From: Ding Tianhong +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 +Acked-by: Mark Rutland +Acked-by: Marc Zyngier +Signed-off-by: Daniel Lezcano +Signed-off-by: Matthias Brugger +--- + 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 0000000..7fe4614 --- /dev/null +++ b/patches.drivers/hns-remove-useless-void-cast.patch @@ -0,0 +1,32 @@ +From: stephen hemminger +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 +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..832011d --- /dev/null +++ b/patches.drivers/net-hns-Add-self-adaptive-interrupt-coalesce-support.patch @@ -0,0 +1,303 @@ +From: Lin Yun Sheng +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 +Tested-by: Weiwei Deng +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..87690a3 --- /dev/null +++ b/patches.drivers/net-hns-Bugfix-for-Tx-timeout-handling-in-hns-driver.patch @@ -0,0 +1,64 @@ +From: Lin Yun Sheng +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 +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..52fad5b --- /dev/null +++ b/patches.drivers/net-hns-Fix-a-skb-used-after-free-bug.patch @@ -0,0 +1,153 @@ +From: Yunsheng Lin +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 +Signed-off-by: lipeng +Reported-by: Jun He +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..6266d2c --- /dev/null +++ b/patches.drivers/net-hns-Fix-a-wrong-op-phy-C45-code.patch @@ -0,0 +1,36 @@ +From: Yunsheng Lin +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 +Reviewed-by: lipeng +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..e55d714 --- /dev/null +++ b/patches.drivers/net-hns-Fix-for-__udivdi3-compiler-error.patch @@ -0,0 +1,35 @@ +From: Lin Yun Sheng +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 +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..819d9c2 --- /dev/null +++ b/patches.drivers/net-hns-Use-phy_driver-to-setup-Phy-loopback.patch @@ -0,0 +1,190 @@ +From: Lin Yun Sheng +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 +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..0bd4446 --- /dev/null +++ b/patches.drivers/net-hns-add-acpi-function-of-xge-led-control.patch @@ -0,0 +1,130 @@ +From: LiuJian +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 +Reviewed-by: John Garry +Reviewed-by: Yunsheng Lin +Reviewed-by: Daode Huang +Signed-off-by: David S. Miller +[mb: change hns_dsaf_acpi_dsm_guid to hns_dsaf_acpi_dsm_uuid] +Signed-off-by: Matthias Brugger +--- + 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 0000000..85a16af --- /dev/null +++ b/patches.drivers/net-hns-set-correct-return-value.patch @@ -0,0 +1,39 @@ +From: Pan Bian +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 +Reviewed-by: Tobias Klauser +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..3e76146 --- /dev/null +++ b/patches.drivers/net-phy-Add-phy-loopback-support-in-net-phy-framewor.patch @@ -0,0 +1,149 @@ +From: Lin Yun Sheng +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 +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +Signed-off-by: Matthias Brugger +--- + 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 0000000..7fd3367 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-add-irq-and-tasklet-cleanup-in-v2-hw.patch @@ -0,0 +1,183 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..335c8c7 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-add-null-check-before-indirect-pointer.patch @@ -0,0 +1,35 @@ +From: "Gustavo A. R. Silva" +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 +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..d07294b --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-add-pci_dev-in-hisi_hba-struct.patch @@ -0,0 +1,543 @@ +From: John Garry +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 +Signed-off-by: Xiang Chen +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 0000000..cab871d --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-add-status-and-command-buffer-for-inte.patch @@ -0,0 +1,58 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..144bb90 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-add-v2-hw-DFX-feature.patch @@ -0,0 +1,104 @@ +From: Xiaofei Tan +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..1434d54 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-avoid-potential-v2-hw-interrupt-issue.patch @@ -0,0 +1,81 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..e4de89e --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-create-hisi_sas_get_fw_info.patch @@ -0,0 +1,179 @@ +From: John Garry +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 +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..8dc58ef --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-define-hisi_sas_device.device_id-as-in.patch @@ -0,0 +1,96 @@ +From: John Garry +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 +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..c9f4481 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-fix-reset-and-port-ID-refresh-issues.patch @@ -0,0 +1,335 @@ +From: Xiaofei Tan +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..a1398ed --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-fix-timeout-check-in-hisi_sas_internal.patch @@ -0,0 +1,73 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..c47da49 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-fix-v2-hw-underflow-residual-value.patch @@ -0,0 +1,44 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..1c9a81a --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-make-several-const-arrays-static.patch @@ -0,0 +1,78 @@ +From: Colin Ian King +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 +Acked-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..54120bf --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-optimise-DMA-slot-memory.patch @@ -0,0 +1,568 @@ +From: Xiaofei Tan +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..a59a2fd --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-optimise-the-usage-of-hisi_hba.lock.patch @@ -0,0 +1,424 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..eafc728 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-redefine-hisi_sas_phy.phy_type-as-u32.patch @@ -0,0 +1,43 @@ +From: John Garry +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..7612b80 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-relocate-get_ata_protocol.patch @@ -0,0 +1,210 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..4ff6ed7 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-relocate-get_ncq_tag_v2_hw.patch @@ -0,0 +1,95 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..3a6692c --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-relocate-sata_done_v2_hw.patch @@ -0,0 +1,105 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..a141dcc --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-remove-driver-versioning.patch @@ -0,0 +1,68 @@ +From: John Garry +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 +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 + #include + +-#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 "); + 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 "); + 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 0000000..a8c4a4e --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-remove-repeated-device-config-in-v2-hw.patch @@ -0,0 +1,62 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..38899d7 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-service-interrupt-ITCT_CLR-interrupt-i.patch @@ -0,0 +1,123 @@ +From: Xiang Chen +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..ebeb670 --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-support-zone-management-commands.patch @@ -0,0 +1,41 @@ +From: Xiaofei Tan +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 +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..90878fa --- /dev/null +++ b/patches.drivers/scsi-hisi_sas-use-array-for-v2-hw-ECC-errors.patch @@ -0,0 +1,436 @@ +From: John Garry +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 +Signed-off-by: Shiju Jose +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0000000..834cea8 --- /dev/null +++ b/patches.drivers/scsi-libsas-move-bus_reset_handler-to-target_reset_h.patch @@ -0,0 +1,148 @@ +From: Hannes Reinecke +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 +Reviewed-by: Christoph Hellwig +Reviewed-by: Johannes Thumshirn +Signed-off-by: Martin K. Petersen +Signed-off-by: Matthias Brugger +--- + 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 0ca4d4c..ee51f1b 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 e598108..8671a2c 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