summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hisi_sas
diff options
context:
space:
mode:
authorXiaofei Tan <tanxiaofei@huawei.com>2018-05-21 18:09:20 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2018-05-28 22:40:32 -0400
commita865ae14ff62797f14b760b2063b90c81d27d178 (patch)
tree1007d145432328d4b4e263b7165e5c9d1161e511 /drivers/scsi/hisi_sas
parent6175abdeaeaf2602f3e92bd4eca5916e98efe996 (diff)
downloadlinux-a865ae14ff62797f14b760b2063b90c81d27d178.tar.bz2
scsi: hisi_sas: Try wait commands before before controller reset
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>
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c19
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c20
4 files changed, 43 insertions, 0 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 37c9a6246dc8..8ce6abb48867 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -246,6 +246,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;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index dc67bd7c7ab0..5bc522c35690 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1293,6 +1293,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);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 8def327c4f46..18dbaffc9988 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -144,6 +144,7 @@
#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
@@ -3501,6 +3502,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,
@@ -3552,6 +3570,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,
};
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 13d21349d1ba..dd5f542bbc45 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -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
@@ -2015,6 +2016,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,
@@ -2063,6 +2082,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 *