Commit 49159a5e authored by Luo Jiaxing's avatar Luo Jiaxing Committed by Martin K. Petersen

scsi: hisi_sas: Take debugfs snapshot for all regs

This patch takes snapshot for global regs, port regs, CQ, DQ, IOST, ITCT.

Add code for snapshot trig and generate dump directory.
Signed-off-by: default avatarLuo Jiaxing <luojiaxing@huawei.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent eb1c2b72
...@@ -223,6 +223,12 @@ struct hisi_sas_slot { ...@@ -223,6 +223,12 @@ struct hisi_sas_slot {
struct hisi_sas_debugfs_reg { struct hisi_sas_debugfs_reg {
int count; 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 { struct hisi_sas_hw {
...@@ -264,8 +270,10 @@ struct hisi_sas_hw { ...@@ -264,8 +270,10 @@ struct hisi_sas_hw {
u32 (*get_phys_state)(struct hisi_hba *hisi_hba); u32 (*get_phys_state)(struct hisi_hba *hisi_hba);
int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type,
u8 reg_index, u8 reg_count, u8 *write_data); u8 reg_index, u8 reg_count, u8 *write_data);
void (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba, int (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba,
int delay_ms, int timeout_ms); int delay_ms, int timeout_ms);
void (*snapshot_prepare)(struct hisi_hba *hisi_hba);
void (*snapshot_restore)(struct hisi_hba *hisi_hba);
int max_command_entries; int max_command_entries;
int complete_hdr_size; int complete_hdr_size;
struct scsi_host_template *sht; struct scsi_host_template *sht;
...@@ -337,6 +345,7 @@ struct hisi_hba { ...@@ -337,6 +345,7 @@ struct hisi_hba {
const struct hisi_sas_hw *hw; /* Low level hw interface */ const struct hisi_sas_hw *hw; /* Low level hw interface */
unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)];
struct work_struct rst_work; struct work_struct rst_work;
struct work_struct debugfs_work;
u32 phy_state; u32 phy_state;
u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ u32 intr_coal_ticks; /* Time of interrupt coalesce in us */
u32 intr_coal_count; /* Interrupt count to coalesce */ u32 intr_coal_count; /* Interrupt count to coalesce */
...@@ -350,6 +359,7 @@ struct hisi_hba { ...@@ -350,6 +359,7 @@ struct hisi_hba {
struct hisi_sas_itct *debugfs_itct; struct hisi_sas_itct *debugfs_itct;
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
struct dentry *debugfs_dump_dentry;
}; };
/* Generic HW DMA host memory structures */ /* Generic HW DMA host memory structures */
...@@ -517,4 +527,5 @@ extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); ...@@ -517,4 +527,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_controller_reset_done(struct hisi_hba *hisi_hba);
extern void hisi_sas_debugfs_init(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_debugfs_exit(struct hisi_hba *hisi_hba);
extern void hisi_sas_debugfs_work_handler(struct work_struct *work);
#endif #endif
...@@ -1429,6 +1429,10 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) ...@@ -1429,6 +1429,10 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
struct Scsi_Host *shost = hisi_hba->shost; struct Scsi_Host *shost = hisi_hba->shost;
int rc; int rc;
if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct &&
!hisi_hba->debugfs_dump_dentry)
queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
if (!hisi_hba->hw->soft_reset) if (!hisi_hba->hw->soft_reset)
return -1; return -1;
...@@ -1923,6 +1927,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, ...@@ -1923,6 +1927,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
slot->task = NULL; slot->task = NULL;
} }
dev_err(dev, "internal task abort: timeout and not done.\n"); dev_err(dev, "internal task abort: timeout and not done.\n");
res = -EIO; res = -EIO;
goto exit; goto exit;
} else } else
...@@ -2459,6 +2464,126 @@ EXPORT_SYMBOL_GPL(hisi_sas_probe); ...@@ -2459,6 +2464,126 @@ EXPORT_SYMBOL_GPL(hisi_sas_probe);
struct dentry *hisi_sas_debugfs_dir; struct dentry *hisi_sas_debugfs_dir;
static void hisi_sas_debugfs_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->debugfs_complete_hdr[i],
hisi_hba->complete_hdr[i],
HISI_SAS_QUEUE_SLOTS * queue_entry_size);
}
static void hisi_sas_debugfs_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->debugfs_cmd_hdr[i],
hisi_hba->cmd_hdr[i],
HISI_SAS_QUEUE_SLOTS * queue_entry_size);
}
static void hisi_sas_debugfs_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->debugfs_port_reg[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_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
{
u32 *databuf = (u32 *)hisi_hba->debugfs_global_reg;
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_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
{
void *databuf = hisi_hba->debugfs_itct;
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_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba)
{
int max_command_entries = hisi_hba->hw->max_command_entries;
void *databuf = hisi_hba->debugfs_iost;
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_debugfs_create_files(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;
hisi_hba->debugfs_dump_dentry = dump_dentry;
return;
fail:
debugfs_remove_recursive(hisi_hba->debugfs_dir);
}
static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba)
{
hisi_hba->hw->snapshot_prepare(hisi_hba);
hisi_sas_debugfs_snapshot_global_reg(hisi_hba);
hisi_sas_debugfs_snapshot_port_reg(hisi_hba);
hisi_sas_debugfs_snapshot_cq_reg(hisi_hba);
hisi_sas_debugfs_snapshot_dq_reg(hisi_hba);
hisi_sas_debugfs_snapshot_itct_reg(hisi_hba);
hisi_sas_debugfs_snapshot_iost_reg(hisi_hba);
hisi_sas_debugfs_create_files(hisi_hba);
hisi_hba->hw->snapshot_restore(hisi_hba);
}
void hisi_sas_debugfs_work_handler(struct work_struct *work)
{
struct hisi_hba *hisi_hba =
container_of(work, struct hisi_hba, debugfs_work);
hisi_sas_debugfs_snapshot_regs(hisi_hba);
}
EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler);
void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
{ {
int max_command_entries = hisi_hba->hw->max_command_entries; int max_command_entries = hisi_hba->hw->max_command_entries;
......
...@@ -3542,8 +3542,8 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, ...@@ -3542,8 +3542,8 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
return 0; return 0;
} }
static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, static int wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
int delay_ms, int timeout_ms) int delay_ms, int timeout_ms)
{ {
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
int entries, entries_old = 0, time; int entries, entries_old = 0, time;
...@@ -3557,7 +3557,12 @@ static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, ...@@ -3557,7 +3557,12 @@ static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
msleep(delay_ms); msleep(delay_ms);
} }
if (time >= timeout_ms)
return -ETIMEDOUT;
dev_dbg(dev, "wait commands complete %dms\n", time); dev_dbg(dev, "wait commands complete %dms\n", time);
return 0;
} }
static struct device_attribute *host_attrs_v2_hw[] = { static struct device_attribute *host_attrs_v2_hw[] = {
......
...@@ -2201,8 +2201,8 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type, ...@@ -2201,8 +2201,8 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type,
return 0; return 0;
} }
static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
int delay_ms, int timeout_ms) int delay_ms, int timeout_ms)
{ {
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
int entries, entries_old = 0, time; int entries, entries_old = 0, time;
...@@ -2216,7 +2216,12 @@ static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, ...@@ -2216,7 +2216,12 @@ static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
msleep(delay_ms); msleep(delay_ms);
} }
if (time >= timeout_ms)
return -ETIMEDOUT;
dev_dbg(dev, "wait commands complete %dms\n", time); dev_dbg(dev, "wait commands complete %dms\n", time);
return 0;
} }
static ssize_t intr_conv_v3_hw_show(struct device *dev, static ssize_t intr_conv_v3_hw_show(struct device *dev,
...@@ -2333,11 +2338,36 @@ static struct device_attribute *host_attrs_v3_hw[] = { ...@@ -2333,11 +2338,36 @@ static struct device_attribute *host_attrs_v3_hw[] = {
}; };
static const struct hisi_sas_debugfs_reg debugfs_port_reg = { 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 = { static const struct hisi_sas_debugfs_reg debugfs_global_reg = {
.read_global_reg = hisi_sas_read32,
}; };
static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
if (wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000) == -ETIMEDOUT)
dev_dbg(dev, "Wait commands complete timeout!\n");
hisi_sas_kill_tasklets(hisi_hba);
}
static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
{
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
(u32)((1ULL << hisi_hba->queue_count) - 1));
clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
}
static struct scsi_host_template sht_v3_hw = { static struct scsi_host_template sht_v3_hw = {
.name = DRV_NAME, .name = DRV_NAME,
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -2388,6 +2418,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { ...@@ -2388,6 +2418,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
.wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw, .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw,
.debugfs_reg_global = &debugfs_global_reg, .debugfs_reg_global = &debugfs_global_reg,
.debugfs_reg_port = &debugfs_port_reg, .debugfs_reg_port = &debugfs_port_reg,
.snapshot_prepare = debugfs_snapshot_prepare_v3_hw,
.snapshot_restore = debugfs_snapshot_restore_v3_hw,
}; };
static struct Scsi_Host * static struct Scsi_Host *
...@@ -2405,6 +2437,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) ...@@ -2405,6 +2437,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
hisi_hba = shost_priv(shost); hisi_hba = shost_priv(shost);
INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
INIT_WORK(&hisi_hba->debugfs_work, hisi_sas_debugfs_work_handler);
hisi_hba->hw = &hisi_sas_v3_hw; hisi_hba->hw = &hisi_sas_v3_hw;
hisi_hba->pci_dev = pdev; hisi_hba->pci_dev = pdev;
hisi_hba->dev = dev; hisi_hba->dev = dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment