diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 4818b7bc220aa1ab949f4d92418012639b7adb73..24492f9b56c43605e19695a4d893395e9ce40677 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 ba0530f8cc98e9f1248eec833472a6eb1602e69e..cb6e041b8233d5700581a9fb2c5f13be5964bcc9 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 986f69d5ad8fc6b12f3dccffe401fccf2ebeb522..8114d76be0e1ec36c77a68e1f907e37867c99e9e 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[] = {