]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
scsi: hisi_sas: Try wait commands before before controller reset
authorXiaofei Tan <tanxiaofei@huawei.com>
Mon, 21 May 2018 10:09:20 +0000 (18:09 +0800)
committerKhalid Elmously <khalid.elmously@canonical.com>
Wed, 6 Jun 2018 19:13:30 +0000 (15:13 -0400)
BugLink: https://bugs.launchpad.net/bugs/1774466
We may reset the controller in many scenarios, such as SCSI EH and HW
errors. There should be no IO which returns from target when SCSI EH is
active. But for other scenarios, there may be.  It is not necessary to make
such IOs fail.

This patch adds an function of trying to wait for any commands, or IO, to
complete before host reset. If no more CQ returned from host controller in
100ms, we assume no more IO can return, and then stop waiting. We wait 5s
at most.

The HW has a register CQE_SEND_CNT to indicate the total number of CQs that
has been reported to driver. We can use this register and it is reliable to
resd this register in such scenarios that require host reset.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
(cherry picked from commit a865ae14ff62797f14b760b2063b90c81d27d178 linux-next)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 21c26d884a62dfeecd2a9470b971bbbbb78af353..521d05e6287935b6edc947a5eca15eae4a8967a8 100644 (file)
@@ -248,6 +248,8 @@ struct hisi_sas_hw {
        u32 (*get_phys_state)(struct hisi_hba *hisi_hba);
        int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type,
                                u8 reg_index, u8 reg_count, u8 *write_data);
+       void (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba,
+                                          int delay_ms, int timeout_ms);
        int max_command_entries;
        int complete_hdr_size;
        struct scsi_host_template *sht;
index c1624c1aa7a760b286e8c709906db8d1f3a42481..aa826e4f158f0470cdfed6d36d309dfce1d19ee4 100644 (file)
@@ -1267,6 +1267,8 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
        old_state = hisi_hba->hw->get_phys_state(hisi_hba);
 
        scsi_block_requests(shost);
+       hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000);
+
        if (timer_pending(&hisi_hba->timer))
                del_timer_sync(&hisi_hba->timer);
 
index 4c06fccc73d0fa93f20700543c87550aefc6db2f..d18937b8c07b8978fa9e90663fa8cb712bba7ab5 100644 (file)
 #define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF       19
 #define SAS_ECC_INTR_MSK               0x1ec
 #define HGC_ERR_STAT_EN                        0x238
+#define CQE_SEND_CNT                   0x248
 #define DLVRY_Q_0_BASE_ADDR_LO         0x260
 #define DLVRY_Q_0_BASE_ADDR_HI         0x264
 #define DLVRY_Q_0_DEPTH                        0x268
@@ -3517,6 +3518,23 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
        return 0;
 }
 
+static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
+                                            int delay_ms, int timeout_ms)
+{
+       struct device *dev = hisi_hba->dev;
+       int entries, entries_old = 0, time;
+
+       for (time = 0; time < timeout_ms; time += delay_ms) {
+               entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT);
+               if (entries == entries_old)
+                       break;
+
+               entries_old = entries;
+               msleep(delay_ms);
+       }
+
+       dev_dbg(dev, "wait commands complete %dms\n", time);
+}
 
 static struct scsi_host_template sht_v2_hw = {
        .name                   = DRV_NAME,
@@ -3568,6 +3586,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
        .soft_reset = soft_reset_v2_hw,
        .get_phys_state = get_phys_state_v2_hw,
        .write_gpio = write_gpio_v2_hw,
+       .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v2_hw,
        .sht = &sht_v2_hw,
 };
 
index af7499617754faf4fdd924d2734b15c179974b68..312be3f4dfb1ecde7812a82c27b471d2c503782b 100644 (file)
@@ -92,6 +92,7 @@
 #define SAS_ECC_INTR                   0x1e8
 #define SAS_ECC_INTR_MSK               0x1ec
 #define HGC_ERR_STAT_EN                        0x238
+#define CQE_SEND_CNT                   0x248
 #define DLVRY_Q_0_BASE_ADDR_LO         0x260
 #define DLVRY_Q_0_BASE_ADDR_HI         0x264
 #define DLVRY_Q_0_DEPTH                        0x268
@@ -2032,6 +2033,24 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type,
        return 0;
 }
 
+static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
+                                            int delay_ms, int timeout_ms)
+{
+       struct device *dev = hisi_hba->dev;
+       int entries, entries_old = 0, time;
+
+       for (time = 0; time < timeout_ms; time += delay_ms) {
+               entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT);
+               if (entries == entries_old)
+                       break;
+
+               entries_old = entries;
+               msleep(delay_ms);
+       }
+
+       dev_dbg(dev, "wait commands complete %dms\n", time);
+}
+
 static struct scsi_host_template sht_v3_hw = {
        .name                   = DRV_NAME,
        .module                 = THIS_MODULE,
@@ -2080,6 +2099,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
        .get_phys_state = get_phys_state_v3_hw,
        .get_events = phy_get_events_v3_hw,
        .write_gpio = write_gpio_v3_hw,
+       .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw,
 };
 
 static struct Scsi_Host *