scsi: hisi_sas: Snapshot HW cache of IOST and ITCT at debugfs
authorLuo Jiaxing <luojiaxing@huawei.com>
Mon, 5 Aug 2019 13:48:01 +0000 (21:48 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 8 Aug 2019 02:13:14 +0000 (22:13 -0400)
The value of IOST/ITCT is updated to cache first, and then synchronize to
DDR periodically. So the value in IOST/ITCT cache is the latest data and
it's important for debugging.

So, the HW cache of IOST and ITCT should be snapshot at debugfs.

Signed-off-by: Luo Jiaxing <luojiaxing@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index c1b56b482a233ed221883bac446483091b80c2f6..5a2fbbbed53ec8262ecb3655c07a3938649638d2 100644 (file)
@@ -36,6 +36,9 @@
 #define HISI_SAS_UNRESERVED_IPTT \
        (HISI_SAS_MAX_COMMANDS - HISI_SAS_RESERVED_IPTT)
 
+#define HISI_SAS_IOST_ITCT_CACHE_NUM 64
+#define HISI_SAS_IOST_ITCT_CACHE_DW_SZ 10
+
 #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer))
 #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table))
 
@@ -252,6 +255,15 @@ struct hisi_sas_debugfs_reg {
        };
 };
 
+struct hisi_sas_iost_itct_cache {
+       u32 data[HISI_SAS_IOST_ITCT_CACHE_DW_SZ];
+};
+
+enum hisi_sas_debugfs_cache_type {
+       HISI_SAS_ITCT_CACHE,
+       HISI_SAS_IOST_CACHE,
+};
+
 struct hisi_sas_hw {
        int (*hw_init)(struct hisi_hba *hisi_hba);
        void (*setup_itct)(struct hisi_hba *hisi_hba,
@@ -294,6 +306,9 @@ struct hisi_sas_hw {
                                          int delay_ms, int timeout_ms);
        void (*snapshot_prepare)(struct hisi_hba *hisi_hba);
        void (*snapshot_restore)(struct hisi_hba *hisi_hba);
+       void (*read_iost_itct_cache)(struct hisi_hba *hisi_hba,
+                                    enum hisi_sas_debugfs_cache_type type,
+                                    u32 *cache);
        int complete_hdr_size;
        struct scsi_host_template *sht;
 
@@ -379,6 +394,8 @@ struct hisi_hba {
        struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES];
        struct hisi_sas_iost *debugfs_iost;
        struct hisi_sas_itct *debugfs_itct;
+       u64 *debugfs_iost_cache;
+       u64 *debugfs_itct_cache;
 
        struct dentry *debugfs_dir;
        struct dentry *debugfs_dump_dentry;
index 325ec4306794d0b1ac5999bc78203a0d5f2d45a5..240b6faaf25f69eaebdce70e3a17b547bd7eb683 100644 (file)
@@ -2763,10 +2763,14 @@ static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
 {
+       void *cachebuf = hisi_hba->debugfs_itct_cache;
        void *databuf = hisi_hba->debugfs_itct;
        struct hisi_sas_itct *itct;
        int i;
 
+       hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE,
+                                          cachebuf);
+
        itct = hisi_hba->itct;
 
        for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
@@ -2778,10 +2782,14 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
 static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba)
 {
        int max_command_entries = HISI_SAS_MAX_COMMANDS;
+       void *cachebuf = hisi_hba->debugfs_iost_cache;
        void *databuf = hisi_hba->debugfs_iost;
        struct hisi_sas_iost *iost;
        int i;
 
+       hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE,
+                                          cachebuf);
+
        iost = hisi_hba->iost;
 
        for (i = 0; i < max_command_entries; i++, iost++) {
@@ -3018,6 +3026,46 @@ static const struct file_operations hisi_sas_debugfs_iost_fops = {
        .owner = THIS_MODULE,
 };
 
+static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p)
+{
+       struct hisi_hba *hisi_hba = s->private;
+       struct hisi_sas_iost_itct_cache *iost_cache =
+               (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_iost_cache;
+       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
+       int i, tab_idx;
+       __le64 *iost;
+
+       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) {
+               /*
+                * Data struct of IOST cache:
+                * Data[1]: BIT0~15: Table index
+                *          Bit16:   Valid mask
+                * Data[2]~[9]: IOST table
+                */
+               tab_idx = (iost_cache->data[1] & 0xffff);
+               iost = (__le64 *)iost_cache;
+
+               hisi_sas_show_row_64(s, tab_idx, cache_size, iost);
+       }
+
+       return 0;
+}
+
+static int hisi_sas_debugfs_iost_cache_open(struct inode *inode,
+                                           struct file *filp)
+{
+       return single_open(filp, hisi_sas_debugfs_iost_cache_show,
+                          inode->i_private);
+}
+
+static const struct file_operations hisi_sas_debugfs_iost_cache_fops = {
+       .open = hisi_sas_debugfs_iost_cache_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
 static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p)
 {
        int i, ret;
@@ -3049,6 +3097,46 @@ static const struct file_operations hisi_sas_debugfs_itct_fops = {
        .owner = THIS_MODULE,
 };
 
+static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p)
+{
+       struct hisi_hba *hisi_hba = s->private;
+       struct hisi_sas_iost_itct_cache *itct_cache =
+               (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_itct_cache;
+       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
+       int i, tab_idx;
+       __le64 *itct;
+
+       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) {
+               /*
+                * Data struct of ITCT cache:
+                * Data[1]: BIT0~15: Table index
+                *          Bit16:   Valid mask
+                * Data[2]~[9]: ITCT table
+                */
+               tab_idx = itct_cache->data[1] & 0xffff;
+               itct = (__le64 *)itct_cache;
+
+               hisi_sas_show_row_64(s, tab_idx, cache_size, itct);
+       }
+
+       return 0;
+}
+
+static int hisi_sas_debugfs_itct_cache_open(struct inode *inode,
+                                           struct file *filp)
+{
+       return single_open(filp, hisi_sas_debugfs_itct_cache_show,
+                          inode->i_private);
+}
+
+static const struct file_operations hisi_sas_debugfs_itct_cache_fops = {
+       .open = hisi_sas_debugfs_itct_cache_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
 static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
 {
        struct dentry *dump_dentry;
@@ -3095,9 +3183,15 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
        debugfs_create_file("iost", 0400, dump_dentry, hisi_hba,
                            &hisi_sas_debugfs_iost_fops);
 
+       debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba,
+                           &hisi_sas_debugfs_iost_cache_fops);
+
        debugfs_create_file("itct", 0400, dump_dentry, hisi_hba,
                            &hisi_sas_debugfs_itct_fops);
 
+       debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba,
+                           &hisi_sas_debugfs_itct_cache_fops);
+
        return;
 }
 
@@ -3212,14 +3306,26 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
                        goto fail_iost_dq;
        }
 
-       /* Alloc buffer for iost */
        sz = max_command_entries * sizeof(struct hisi_sas_iost);
 
        hisi_hba->debugfs_iost = devm_kmalloc(dev, sz, GFP_KERNEL);
        if (!hisi_hba->debugfs_iost)
                goto fail_iost_dq;
 
-       /* Alloc buffer for itct */
+       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+            sizeof(struct hisi_sas_iost_itct_cache);
+
+       hisi_hba->debugfs_iost_cache = devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_iost_cache)
+               goto fail_iost_cache;
+
+       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+            sizeof(struct hisi_sas_iost_itct_cache);
+
+       hisi_hba->debugfs_itct_cache = devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_itct_cache)
+               goto fail_itct_cache;
+
        /* New memory allocation must be locate before itct */
        sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
 
@@ -3229,6 +3335,10 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
 
        return;
 fail_itct:
+       devm_kfree(dev, hisi_hba->debugfs_iost_cache);
+fail_itct_cache:
+       devm_kfree(dev, hisi_hba->debugfs_iost_cache);
+fail_iost_cache:
        devm_kfree(dev, hisi_hba->debugfs_iost);
 fail_iost_dq:
        for (i = 0; i < d; i++)
index b99abc788487c40d7aecfa2979a5d353bcdbacb0..c8ca6ead639bf7c038c95b0e799267f7d4c3fe12 100644 (file)
@@ -71,6 +71,7 @@
 #define HGC_DQE_ECC_MB_ADDR_OFF        16
 #define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF)
 #define CHNL_INT_STATUS                        0x148
+#define TAB_DFX                                0x14c
 #define HGC_ITCT_ECC_ADDR              0x150
 #define HGC_ITCT_ECC_1B_ADDR_OFF               0
 #define HGC_ITCT_ECC_1B_ADDR_MSK               (0x3ff << \
@@ -83,6 +84,7 @@
 #define AXI_ERR_INFO_MSK               (0xff << AXI_ERR_INFO_OFF)
 #define FIFO_ERR_INFO_OFF              8
 #define FIFO_ERR_INFO_MSK              (0xff << FIFO_ERR_INFO_OFF)
+#define TAB_RD_TYPE                    0x15c
 #define INT_COAL_EN                    0x19c
 #define OQ_INT_COAL_TIME               0x1a0
 #define OQ_INT_COAL_CNT                        0x1a4
@@ -2877,6 +2879,35 @@ static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
        clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
 }
 
+static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba,
+                                      enum hisi_sas_debugfs_cache_type type,
+                                      u32 *cache)
+{
+       u32 cache_dw_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ *
+                           HISI_SAS_IOST_ITCT_CACHE_NUM;
+       u32 *buf = cache;
+       u32 i, val;
+
+       hisi_sas_write32(hisi_hba, TAB_RD_TYPE, type);
+
+       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_DW_SZ; i++) {
+               val = hisi_sas_read32(hisi_hba, TAB_DFX);
+               if (val == 0xffffffff)
+                       break;
+       }
+
+       if (val != 0xffffffff) {
+               pr_err("Issue occur when reading IOST/ITCT cache!\n");
+               return;
+       }
+
+       memset(buf, 0, cache_dw_size * 4);
+       buf[0] = val;
+
+       for (i = 1; i < cache_dw_size; i++)
+               buf[i] = hisi_sas_read32(hisi_hba, TAB_DFX);
+}
+
 static struct scsi_host_template sht_v3_hw = {
        .name                   = DRV_NAME,
        .module                 = THIS_MODULE,
@@ -2929,6 +2960,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
        .debugfs_reg_port = &debugfs_port_reg,
        .snapshot_prepare = debugfs_snapshot_prepare_v3_hw,
        .snapshot_restore = debugfs_snapshot_restore_v3_hw,
+       .read_iost_itct_cache = read_iost_itct_cache_v3_hw,
 };
 
 static struct Scsi_Host *