From 583194c8fe8fa3e32a05346839e9d32181f48571 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Mon, 5 Nov 2018 16:01:02 +0800 Subject: [PATCH] scsi: hisi_sas: Add DFX Feature: Take snapshot for all regs and add snapshot trig This patch take snapshot for global regs, port regs, CQ, DQ, IOST, ITCT. Then, Add code for snapshot trig and generate dump directory. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 8 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 114 +++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 + 3 files changed, 125 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 4818b7bc220a..24492f9b56c4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -225,6 +225,13 @@ struct hisi_sas_slot { struct hisi_sas_debugfs_reg { int count; + int base_off; + union { + u32 (*read_global_reg)(struct hisi_hba *hisi_hba, u32 off); + u32 (*read_port_reg)(struct hisi_hba *hisi_hba, + int port, + u32 off); + }; }; struct hisi_sas_hw { @@ -526,4 +533,5 @@ extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); extern void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba); extern void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba); extern void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba); +extern void hisi_sas_snapshot_regs(struct hisi_hba *hisi_hba); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ba0530f8cc98..cb6e041b8233 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1526,6 +1526,9 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) struct Scsi_Host *shost = hisi_hba->shost; int rc; + if (hisi_sas_debugfs_enable && hisi_hba->itct_debugfs) + hisi_sas_snapshot_regs(hisi_hba); + if (!hisi_hba->hw->soft_reset) return -1; @@ -2020,6 +2023,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, slot->task = NULL; } dev_err(dev, "internal task abort: timeout and not done.\n"); + res = -EIO; goto exit; } else @@ -2574,6 +2578,116 @@ EXPORT_SYMBOL_GPL(hisi_sas_probe); struct dentry *hisi_sas_dbg_dir; +static void hisi_sas_snapshot_cq_reg(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + memcpy(hisi_hba->complete_hdr_debugfs[i], + hisi_hba->complete_hdr[i], + HISI_SAS_QUEUE_SLOTS * queue_entry_size); +} + + +static void hisi_sas_snapshot_dq_reg(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + memcpy(hisi_hba->cmd_hdr_debugfs[i], + hisi_hba->cmd_hdr[i], + HISI_SAS_QUEUE_SLOTS * queue_entry_size); +} + +static void hisi_sas_snapshot_port_reg(struct hisi_hba *hisi_hba) +{ + const struct hisi_sas_debugfs_reg *port = + hisi_hba->hw->debugfs_reg_port; + int i, phy_cnt; + u32 offset; + u32 *databuf; + + for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { + databuf = (u32 *)hisi_hba->port_reg_debugfs[phy_cnt]; + for (i = 0; i < port->count; i++, databuf++) { + offset = port->base_off + 4 * i; + *databuf = port->read_port_reg(hisi_hba, + phy_cnt, + offset); + } + } +} + +static void hisi_sas_snapshot_global_reg(struct hisi_hba *hisi_hba) +{ + u32 *databuf = (u32 *)hisi_hba->global_reg_debugfs; + const struct hisi_sas_debugfs_reg *global = + hisi_hba->hw->debugfs_reg_global; + int i; + + for (i = 0; i < global->count; i++, databuf++) + *databuf = global->read_global_reg(hisi_hba, + 4 * i); +} + +static void hisi_sas_snapshot_itct_reg(struct hisi_hba *hisi_hba) +{ + void *databuf = hisi_hba->itct_debugfs; + struct hisi_sas_itct *itct; + int i; + + itct = hisi_hba->itct; + + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { + memcpy(databuf, itct, sizeof(struct hisi_sas_itct)); + databuf += sizeof(struct hisi_sas_itct); + } +} + +static void hisi_sas_snapshot_iost_reg(struct hisi_hba *hisi_hba) +{ + int max_command_entries = hisi_hba->hw->max_command_entries; + void *databuf = hisi_hba->iost_debugfs; + struct hisi_sas_iost *iost; + int i; + + iost = hisi_hba->iost; + + for (i = 0; i < max_command_entries; i++, iost++) { + memcpy(databuf, iost, sizeof(struct hisi_sas_iost)); + databuf += sizeof(struct hisi_sas_iost); + } +} + +static void hisi_sas_create_folder_structure(struct hisi_hba *hisi_hba) +{ + struct dentry *dump_dentry; + + /* Create dump dir inside device dir */ + dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); + if (!dump_dentry) + goto fail; + + return; +fail: + debugfs_remove_recursive(hisi_hba->debugfs_dir); +} + +void hisi_sas_snapshot_regs(struct hisi_hba *hisi_hba) +{ + hisi_sas_snapshot_global_reg(hisi_hba); + hisi_sas_snapshot_port_reg(hisi_hba); + hisi_sas_snapshot_cq_reg(hisi_hba); + hisi_sas_snapshot_dq_reg(hisi_hba); + hisi_sas_snapshot_itct_reg(hisi_hba); + hisi_sas_snapshot_iost_reg(hisi_hba); + + hisi_sas_create_folder_structure(hisi_hba); +} +EXPORT_SYMBOL_GPL(hisi_sas_snapshot_regs); + void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) { int max_command_entries = hisi_hba->hw->max_command_entries; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 986f69d5ad8f..8114d76be0e1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2401,9 +2401,12 @@ static ssize_t intr_coal_count_store(struct device *dev, static DEVICE_ATTR_RW(intr_coal_count); static const struct hisi_sas_debugfs_reg debugfs_port_reg = { + .base_off = PORT_BASE, + .read_port_reg = hisi_sas_phy_read32, }; static const struct hisi_sas_debugfs_reg debugfs_global_reg = { + .read_global_reg = hisi_sas_read32, }; struct device_attribute *host_attrs_v3_hw[] = { -- GitLab