summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hisi_sas
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 13:34:31 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 13:34:31 -0800
commit60f7c503d971a731ee3c4f884a9f2e80d476730d (patch)
tree30e23c822306b0e407f6218135feb5b2e847665d /drivers/scsi/hisi_sas
parent69f637c33560b02ae7313e0c142d847361cc723a (diff)
parentbe1b500212541a70006887bae558ff834d7365d0 (diff)
downloadlinux-60f7c503d971a731ee3c4f884a9f2e80d476730d.tar.gz
linux-60f7c503d971a731ee3c4f884a9f2e80d476730d.tar.bz2
linux-60f7c503d971a731ee3c4f884a9f2e80d476730d.zip
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "This consists of the usual driver updates (ufs, qla2xxx, smartpqi, target, zfcp, fnic, mpt3sas, ibmvfc) plus a load of cleanups, a major power management rework and a load of assorted minor updates. There are a few core updates (formatting fixes being the big one) but nothing major this cycle" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (279 commits) scsi: mpt3sas: Update driver version to 36.100.00.00 scsi: mpt3sas: Handle trigger page after firmware update scsi: mpt3sas: Add persistent MPI trigger page scsi: mpt3sas: Add persistent SCSI sense trigger page scsi: mpt3sas: Add persistent Event trigger page scsi: mpt3sas: Add persistent Master trigger page scsi: mpt3sas: Add persistent trigger pages support scsi: mpt3sas: Sync time periodically between driver and firmware scsi: qla2xxx: Update version to 10.02.00.104-k scsi: qla2xxx: Fix device loss on 4G and older HBAs scsi: qla2xxx: If fcport is undergoing deletion complete I/O with retry scsi: qla2xxx: Fix the call trace for flush workqueue scsi: qla2xxx: Fix flash update in 28XX adapters on big endian machines scsi: qla2xxx: Handle aborts correctly for port undergoing deletion scsi: qla2xxx: Fix N2N and NVMe connect retry failure scsi: qla2xxx: Fix FW initialization error on big endian machines scsi: qla2xxx: Fix crash during driver load on big endian machines scsi: qla2xxx: Fix compilation issue in PPC systems scsi: qla2xxx: Don't check for fw_started while posting NVMe command scsi: qla2xxx: Tear down session if FW say it is down ...
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h28
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c1354
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c1295
3 files changed, 1232 insertions, 1445 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index a25cfc11c96d..2b28dd405600 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -243,24 +243,6 @@ struct hisi_sas_slot {
u16 idx;
};
-#define HISI_SAS_DEBUGFS_REG(x) {#x, x}
-
-struct hisi_sas_debugfs_reg_lu {
- char *name;
- int off;
-};
-
-struct hisi_sas_debugfs_reg {
- const struct hisi_sas_debugfs_reg_lu *lu;
- 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_iost_itct_cache {
u32 data[HISI_SAS_IOST_ITCT_CACHE_DW_SZ];
};
@@ -350,15 +332,8 @@ 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);
- int (*set_bist)(struct hisi_hba *hisi_hba, bool enable);
- 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;
-
- const struct hisi_sas_debugfs_reg *debugfs_reg_array[DEBUGFS_REGS_NUM];
- const struct hisi_sas_debugfs_reg *debugfs_reg_port;
};
#define HISI_SAS_MAX_DEBUGFS_DUMP (50)
@@ -673,7 +648,4 @@ extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max);
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_debugfs_work_handler(struct work_struct *work);
#endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 274ccf18ce2d..b6d4419c32f2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -591,13 +591,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
dev = hisi_hba->dev;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
- /*
- * For IOs from upper layer, it may already disable preempt
- * in the IO path, if disable preempt again in down(),
- * function schedule() will report schedule_bug(), so check
- * preemptible() before goto down().
- */
- if (!preemptible())
+ if (!gfpflags_allow_blocking(gfp_flags))
return -EINVAL;
down(&hisi_hba->sem);
@@ -2696,1355 +2690,12 @@ int hisi_sas_probe(struct platform_device *pdev,
err_out_register_ha:
scsi_remove_host(shost);
err_out_ha:
- hisi_sas_debugfs_exit(hisi_hba);
hisi_sas_free(hisi_hba);
scsi_host_put(shost);
return rc;
}
EXPORT_SYMBOL_GPL(hisi_sas_probe);
-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 dump_index = hisi_hba->debugfs_dump_index;
- int i;
-
- for (i = 0; i < hisi_hba->queue_count; i++)
- memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
- 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 = sizeof(struct hisi_sas_cmd_hdr);
- int dump_index = hisi_hba->debugfs_dump_index;
- int i;
-
- for (i = 0; i < hisi_hba->queue_count; i++) {
- struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
- int j;
-
- debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
- cmd_hdr = hisi_hba->cmd_hdr[i];
-
- for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
- memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j],
- queue_entry_size);
- }
-}
-
-static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
-{
- int dump_index = hisi_hba->debugfs_dump_index;
- 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 = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
- 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)
-{
- int dump_index = hisi_hba->debugfs_dump_index;
- u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const struct hisi_sas_debugfs_reg *global =
- hw->debugfs_reg_array[DEBUGFS_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_axi_reg(struct hisi_hba *hisi_hba)
-{
- int dump_index = hisi_hba->debugfs_dump_index;
- u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const struct hisi_sas_debugfs_reg *axi =
- hw->debugfs_reg_array[DEBUGFS_AXI];
- int i;
-
- for (i = 0; i < axi->count; i++, databuf++)
- *databuf = axi->read_global_reg(hisi_hba,
- 4 * i + axi->base_off);
-}
-
-static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba)
-{
- int dump_index = hisi_hba->debugfs_dump_index;
- u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const struct hisi_sas_debugfs_reg *ras =
- hw->debugfs_reg_array[DEBUGFS_RAS];
- int i;
-
- for (i = 0; i < ras->count; i++, databuf++)
- *databuf = ras->read_global_reg(hisi_hba,
- 4 * i + ras->base_off);
-}
-
-static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
-{
- int dump_index = hisi_hba->debugfs_dump_index;
- void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
- void *databuf = hisi_hba->debugfs_itct[dump_index].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++) {
- 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 dump_index = hisi_hba->debugfs_dump_index;
- int max_command_entries = HISI_SAS_MAX_COMMANDS;
- void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
- void *databuf = hisi_hba->debugfs_iost[dump_index].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++) {
- memcpy(databuf, iost, sizeof(struct hisi_sas_iost));
- databuf += sizeof(struct hisi_sas_iost);
- }
-}
-
-static const char *
-hisi_sas_debugfs_to_reg_name(int off, int base_off,
- const struct hisi_sas_debugfs_reg_lu *lu)
-{
- for (; lu->name; lu++) {
- if (off == lu->off - base_off)
- return lu->name;
- }
-
- return NULL;
-}
-
-static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr,
- struct seq_file *s)
-{
- const struct hisi_sas_debugfs_reg *reg = ptr;
- int i;
-
- for (i = 0; i < reg->count; i++) {
- int off = i * 4;
- const char *name;
-
- name = hisi_sas_debugfs_to_reg_name(off, reg->base_off,
- reg->lu);
-
- if (name)
- seq_printf(s, "0x%08x 0x%08x %s\n", off,
- regs_val[i], name);
- else
- seq_printf(s, "0x%08x 0x%08x\n", off,
- regs_val[i]);
- }
-}
-
-static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_regs *global = s->private;
- struct hisi_hba *hisi_hba = global->hisi_hba;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL];
-
- hisi_sas_debugfs_print_reg(global->data,
- reg_global, s);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_global_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_global_fops = {
- .open = hisi_sas_debugfs_global_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_regs *axi = s->private;
- struct hisi_hba *hisi_hba = axi->hisi_hba;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI];
-
- hisi_sas_debugfs_print_reg(axi->data,
- reg_axi, s);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_axi_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_axi_fops = {
- .open = hisi_sas_debugfs_axi_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_regs *ras = s->private;
- struct hisi_hba *hisi_hba = ras->hisi_hba;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS];
-
- hisi_sas_debugfs_print_reg(ras->data,
- reg_ras, s);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_ras_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_ras_fops = {
- .open = hisi_sas_debugfs_ras_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_port *port = s->private;
- struct hisi_sas_phy *phy = port->phy;
- struct hisi_hba *hisi_hba = phy->hisi_hba;
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port;
-
- hisi_sas_debugfs_print_reg(port->data, reg_port, s);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_port_fops = {
- .open = hisi_sas_debugfs_port_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static void hisi_sas_show_row_64(struct seq_file *s, int index,
- int sz, __le64 *ptr)
-{
- int i;
-
- /* completion header size not fixed per HW version */
- seq_printf(s, "index %04d:\n\t", index);
- for (i = 1; i <= sz / 8; i++, ptr++) {
- seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr));
- if (!(i % 2))
- seq_puts(s, "\n\t");
- }
-
- seq_puts(s, "\n");
-}
-
-static void hisi_sas_show_row_32(struct seq_file *s, int index,
- int sz, __le32 *ptr)
-{
- int i;
-
- /* completion header size not fixed per HW version */
- seq_printf(s, "index %04d:\n\t", index);
- for (i = 1; i <= sz / 4; i++, ptr++) {
- seq_printf(s, " 0x%08x", le32_to_cpu(*ptr));
- if (!(i % 4))
- seq_puts(s, "\n\t");
- }
- seq_puts(s, "\n");
-}
-
-static void hisi_sas_cq_show_slot(struct seq_file *s, int slot,
- struct hisi_sas_debugfs_cq *debugfs_cq)
-{
- struct hisi_sas_cq *cq = debugfs_cq->cq;
- struct hisi_hba *hisi_hba = cq->hisi_hba;
- __le32 *complete_hdr = debugfs_cq->complete_hdr +
- (hisi_hba->hw->complete_hdr_size * slot);
-
- hisi_sas_show_row_32(s, slot,
- hisi_hba->hw->complete_hdr_size,
- complete_hdr);
-}
-
-static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
- int slot;
-
- for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
- hisi_sas_cq_show_slot(s, slot, debugfs_cq);
- }
- return 0;
-}
-
-static int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_cq_fops = {
- .open = hisi_sas_debugfs_cq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr)
-{
- struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
- void *cmd_queue = debugfs_dq->hdr;
- __le32 *cmd_hdr = cmd_queue +
- sizeof(struct hisi_sas_cmd_hdr) * slot;
-
- hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr);
-}
-
-static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p)
-{
- int slot;
-
- for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
- hisi_sas_dq_show_slot(s, slot, s->private);
- }
- return 0;
-}
-
-static int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_dq_fops = {
- .open = hisi_sas_debugfs_dq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
- struct hisi_sas_iost *iost = debugfs_iost->iost;
- int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
-
- for (i = 0; i < max_command_entries; i++, iost++) {
- __le64 *data = &iost->qw0;
-
- hisi_sas_show_row_64(s, i, sizeof(*iost), data);
- }
-
- return 0;
-}
-
-static int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_iost_fops = {
- .open = hisi_sas_debugfs_iost_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
- struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->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;
- struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
- struct hisi_sas_itct *itct = debugfs_itct->itct;
-
- for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
- __le64 *data = &itct->qw0;
-
- hisi_sas_show_row_64(s, i, sizeof(*itct), data);
- }
-
- return 0;
-}
-
-static int hisi_sas_debugfs_itct_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_itct_show, inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_itct_fops = {
- .open = hisi_sas_debugfs_itct_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
- struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->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)
-{
- u64 *debugfs_timestamp;
- int dump_index = hisi_hba->debugfs_dump_index;
- struct dentry *dump_dentry;
- struct dentry *dentry;
- char name[256];
- int p;
- int c;
- int d;
-
- snprintf(name, 256, "%d", dump_index);
-
- dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
-
- debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
-
- debugfs_create_u64("timestamp", 0400, dump_dentry,
- debugfs_timestamp);
-
- debugfs_create_file("global", 0400, dump_dentry,
- &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
- &hisi_sas_debugfs_global_fops);
-
- /* Create port dir and files */
- dentry = debugfs_create_dir("port", dump_dentry);
- for (p = 0; p < hisi_hba->n_phy; p++) {
- snprintf(name, 256, "%d", p);
-
- debugfs_create_file(name, 0400, dentry,
- &hisi_hba->debugfs_port_reg[dump_index][p],
- &hisi_sas_debugfs_port_fops);
- }
-
- /* Create CQ dir and files */
- dentry = debugfs_create_dir("cq", dump_dentry);
- for (c = 0; c < hisi_hba->queue_count; c++) {
- snprintf(name, 256, "%d", c);
-
- debugfs_create_file(name, 0400, dentry,
- &hisi_hba->debugfs_cq[dump_index][c],
- &hisi_sas_debugfs_cq_fops);
- }
-
- /* Create DQ dir and files */
- dentry = debugfs_create_dir("dq", dump_dentry);
- for (d = 0; d < hisi_hba->queue_count; d++) {
- snprintf(name, 256, "%d", d);
-
- debugfs_create_file(name, 0400, dentry,
- &hisi_hba->debugfs_dq[dump_index][d],
- &hisi_sas_debugfs_dq_fops);
- }
-
- debugfs_create_file("iost", 0400, dump_dentry,
- &hisi_hba->debugfs_iost[dump_index],
- &hisi_sas_debugfs_iost_fops);
-
- debugfs_create_file("iost_cache", 0400, dump_dentry,
- &hisi_hba->debugfs_iost_cache[dump_index],
- &hisi_sas_debugfs_iost_cache_fops);
-
- debugfs_create_file("itct", 0400, dump_dentry,
- &hisi_hba->debugfs_itct[dump_index],
- &hisi_sas_debugfs_itct_fops);
-
- debugfs_create_file("itct_cache", 0400, dump_dentry,
- &hisi_hba->debugfs_itct_cache[dump_index],
- &hisi_sas_debugfs_itct_cache_fops);
-
- debugfs_create_file("axi", 0400, dump_dentry,
- &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
- &hisi_sas_debugfs_axi_fops);
-
- debugfs_create_file("ras", 0400, dump_dentry,
- &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
- &hisi_sas_debugfs_ras_fops);
-
- return;
-}
-
-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_axi_reg(hisi_hba);
- hisi_sas_debugfs_snapshot_ras_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);
-}
-
-static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hisi_hba *hisi_hba = file->f_inode->i_private;
- char buf[8];
-
- if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
- return -EFAULT;
-
- if (count > 8)
- return -EFAULT;
-
- if (copy_from_user(buf, user_buf, count))
- return -EFAULT;
-
- if (buf[0] != '1')
- return -EFAULT;
-
- queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
-
- return count;
-}
-
-static const struct file_operations hisi_sas_debugfs_trigger_dump_fops = {
- .write = &hisi_sas_debugfs_trigger_dump_write,
- .owner = THIS_MODULE,
-};
-
-enum {
- HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0,
- HISI_SAS_BIST_LOOPBACK_MODE_SERDES,
- HISI_SAS_BIST_LOOPBACK_MODE_REMOTE,
-};
-
-static const struct {
- int value;
- char *name;
-} hisi_sas_debugfs_loop_linkrate[] = {
- { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
- { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
- { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
- { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
-};
-
-static int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p)
-{
- struct hisi_hba *hisi_hba = s->private;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
- int match = (hisi_hba->debugfs_bist_linkrate ==
- hisi_sas_debugfs_loop_linkrate[i].value);
-
- seq_printf(s, "%s%s%s ", match ? "[" : "",
- hisi_sas_debugfs_loop_linkrate[i].name,
- match ? "]" : "");
- }
- seq_puts(s, "\n");
-
- return 0;
-}
-
-static ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- struct hisi_hba *hisi_hba = m->private;
- char kbuf[16] = {}, *pkbuf;
- bool found = false;
- int i;
-
- if (hisi_hba->debugfs_bist_enable)
- return -EPERM;
-
- if (count >= sizeof(kbuf))
- return -EOVERFLOW;
-
- if (copy_from_user(kbuf, buf, count))
- return -EINVAL;
-
- pkbuf = strstrip(kbuf);
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
- if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name,
- pkbuf, 16)) {
- hisi_hba->debugfs_bist_linkrate =
- hisi_sas_debugfs_loop_linkrate[i].value;
- found = true;
- break;
- }
- }
-
- if (!found)
- return -EINVAL;
-
- return count;
-}
-
-static int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_bist_linkrate_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = {
- .open = hisi_sas_debugfs_bist_linkrate_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_bist_linkrate_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct {
- int value;
- char *name;
-} hisi_sas_debugfs_loop_code_mode[] = {
- { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" },
- { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" },
- { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" },
- { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" },
- { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" },
- { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" },
- { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" },
- { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" },
- { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" },
- { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" },
- { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" },
- { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" },
-};
-
-static int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p)
-{
- struct hisi_hba *hisi_hba = s->private;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
- int match = (hisi_hba->debugfs_bist_code_mode ==
- hisi_sas_debugfs_loop_code_mode[i].value);
-
- seq_printf(s, "%s%s%s ", match ? "[" : "",
- hisi_sas_debugfs_loop_code_mode[i].name,
- match ? "]" : "");
- }
- seq_puts(s, "\n");
-
- return 0;
-}
-
-static ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- struct hisi_hba *hisi_hba = m->private;
- char kbuf[16] = {}, *pkbuf;
- bool found = false;
- int i;
-
- if (hisi_hba->debugfs_bist_enable)
- return -EPERM;
-
- if (count >= sizeof(kbuf))
- return -EINVAL;
-
- if (copy_from_user(kbuf, buf, count))
- return -EOVERFLOW;
-
- pkbuf = strstrip(kbuf);
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
- if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name,
- pkbuf, 16)) {
- hisi_hba->debugfs_bist_code_mode =
- hisi_sas_debugfs_loop_code_mode[i].value;
- found = true;
- break;
- }
- }
-
- if (!found)
- return -EINVAL;
-
- return count;
-}
-
-static int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_bist_code_mode_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = {
- .open = hisi_sas_debugfs_bist_code_mode_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_bist_code_mode_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- struct hisi_hba *hisi_hba = m->private;
- unsigned int phy_no;
- int val;
-
- if (hisi_hba->debugfs_bist_enable)
- return -EPERM;
-
- val = kstrtouint_from_user(buf, count, 0, &phy_no);
- if (val)
- return val;
-
- if (phy_no >= hisi_hba->n_phy)
- return -EINVAL;
-
- hisi_hba->debugfs_bist_phy_no = phy_no;
-
- return count;
-}
-
-static int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p)
-{
- struct hisi_hba *hisi_hba = s->private;
-
- seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_bist_phy_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_bist_phy_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_bist_phy_ops = {
- .open = hisi_sas_debugfs_bist_phy_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_bist_phy_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct {
- int value;
- char *name;
-} hisi_sas_debugfs_loop_modes[] = {
- { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
- { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
- { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
-};
-
-static int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p)
-{
- struct hisi_hba *hisi_hba = s->private;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
- int match = (hisi_hba->debugfs_bist_mode ==
- hisi_sas_debugfs_loop_modes[i].value);
-
- seq_printf(s, "%s%s%s ", match ? "[" : "",
- hisi_sas_debugfs_loop_modes[i].name,
- match ? "]" : "");
- }
- seq_puts(s, "\n");
-
- return 0;
-}
-
-static ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- struct hisi_hba *hisi_hba = m->private;
- char kbuf[16] = {}, *pkbuf;
- bool found = false;
- int i;
-
- if (hisi_hba->debugfs_bist_enable)
- return -EPERM;
-
- if (count >= sizeof(kbuf))
- return -EINVAL;
-
- if (copy_from_user(kbuf, buf, count))
- return -EOVERFLOW;
-
- pkbuf = strstrip(kbuf);
-
- for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
- if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) {
- hisi_hba->debugfs_bist_mode =
- hisi_sas_debugfs_loop_modes[i].value;
- found = true;
- break;
- }
- }
-
- if (!found)
- return -EINVAL;
-
- return count;
-}
-
-static int hisi_sas_debugfs_bist_mode_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_bist_mode_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_bist_mode_ops = {
- .open = hisi_sas_debugfs_bist_mode_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_bist_mode_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- struct hisi_hba *hisi_hba = m->private;
- unsigned int enable;
- int val;
-
- val = kstrtouint_from_user(buf, count, 0, &enable);
- if (val)
- return val;
-
- if (enable > 1)
- return -EINVAL;
-
- if (enable == hisi_hba->debugfs_bist_enable)
- return count;
-
- if (!hisi_hba->hw->set_bist)
- return -EPERM;
-
- val = hisi_hba->hw->set_bist(hisi_hba, enable);
- if (val < 0)
- return val;
-
- hisi_hba->debugfs_bist_enable = enable;
-
- return count;
-}
-
-static int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p)
-{
- struct hisi_hba *hisi_hba = s->private;
-
- seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_bist_enable_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_bist_enable_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_bist_enable_ops = {
- .open = hisi_sas_debugfs_bist_enable_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_bist_enable_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct {
- char *name;
-} hisi_sas_debugfs_ffe_name[FFE_CFG_MAX] = {
- { "SAS_1_5_GBPS" },
- { "SAS_3_0_GBPS" },
- { "SAS_6_0_GBPS" },
- { "SAS_12_0_GBPS" },
- { "FFE_RESV" },
- { "SATA_1_5_GBPS" },
- { "SATA_3_0_GBPS" },
- { "SATA_6_0_GBPS" },
-};
-
-static ssize_t hisi_sas_debugfs_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *m = filp->private_data;
- u32 *val = m->private;
- int res;
-
- res = kstrtouint_from_user(buf, count, 0, val);
- if (res)
- return res;
-
- return count;
-}
-
-static int hisi_sas_debugfs_show(struct seq_file *s, void *p)
-{
- u32 *val = s->private;
-
- seq_printf(s, "0x%x\n", *val);
-
- return 0;
-}
-
-static int hisi_sas_debugfs_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_ops = {
- .open = hisi_sas_debugfs_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *s = filp->private_data;
- struct hisi_sas_phy *phy = s->private;
- unsigned int set_val;
- int res;
-
- res = kstrtouint_from_user(buf, count, 0, &set_val);
- if (res)
- return res;
-
- if (set_val > 0)
- return -EINVAL;
-
- atomic_set(&phy->down_cnt, 0);
-
- return count;
-}
-
-static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p)
-{
- struct hisi_sas_phy *phy = s->private;
-
- seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
-
- return 0;
-}
-
-static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode,
- struct file *filp)
-{
- return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show,
- inode->i_private);
-}
-
-static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = {
- .open = hisi_sas_debugfs_phy_down_cnt_open,
- .read = seq_read,
- .write = hisi_sas_debugfs_phy_down_cnt_write,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-void hisi_sas_debugfs_work_handler(struct work_struct *work)
-{
- struct hisi_hba *hisi_hba =
- container_of(work, struct hisi_hba, debugfs_work);
- int debugfs_dump_index = hisi_hba->debugfs_dump_index;
- struct device *dev = hisi_hba->dev;
- u64 timestamp = local_clock();
-
- if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
- dev_warn(dev, "dump count exceeded!\n");
- return;
- }
-
- do_div(timestamp, NSEC_PER_MSEC);
- hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
-
- hisi_sas_debugfs_snapshot_regs(hisi_hba);
- hisi_hba->debugfs_dump_index++;
-}
-EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler);
-
-static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index)
-{
- struct device *dev = hisi_hba->dev;
- int i;
-
- devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
- devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
- devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
- devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
-
- for (i = 0; i < hisi_hba->queue_count; i++)
- devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
-
- for (i = 0; i < hisi_hba->queue_count; i++)
- devm_kfree(dev,
- hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
-
- for (i = 0; i < DEBUGFS_REGS_NUM; i++)
- devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
-
- for (i = 0; i < hisi_hba->n_phy; i++)
- devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
-}
-
-static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index)
-{
- const struct hisi_sas_hw *hw = hisi_hba->hw;
- struct device *dev = hisi_hba->dev;
- int p, c, d, r, i;
- size_t sz;
-
- for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
- struct hisi_sas_debugfs_regs *regs =
- &hisi_hba->debugfs_regs[dump_index][r];
-
- sz = hw->debugfs_reg_array[r]->count * 4;
- regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!regs->data)
- goto fail;
- regs->hisi_hba = hisi_hba;
- }
-
- sz = hw->debugfs_reg_port->count * 4;
- for (p = 0; p < hisi_hba->n_phy; p++) {
- struct hisi_sas_debugfs_port *port =
- &hisi_hba->debugfs_port_reg[dump_index][p];
-
- port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!port->data)
- goto fail;
- port->phy = &hisi_hba->phy[p];
- }
-
- sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
- for (c = 0; c < hisi_hba->queue_count; c++) {
- struct hisi_sas_debugfs_cq *cq =
- &hisi_hba->debugfs_cq[dump_index][c];
-
- cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!cq->complete_hdr)
- goto fail;
- cq->cq = &hisi_hba->cq[c];
- }
-
- sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
- for (d = 0; d < hisi_hba->queue_count; d++) {
- struct hisi_sas_debugfs_dq *dq =
- &hisi_hba->debugfs_dq[dump_index][d];
-
- dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!dq->hdr)
- goto fail;
- dq->dq = &hisi_hba->dq[d];
- }
-
- sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
-
- hisi_hba->debugfs_iost[dump_index].iost =
- devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!hisi_hba->debugfs_iost[dump_index].iost)
- goto fail;
-
- sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
- sizeof(struct hisi_sas_iost_itct_cache);
-
- hisi_hba->debugfs_iost_cache[dump_index].cache =
- devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
- goto fail;
-
- sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
- sizeof(struct hisi_sas_iost_itct_cache);
-
- hisi_hba->debugfs_itct_cache[dump_index].cache =
- devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
- goto fail;
-
- /* New memory allocation must be locate before itct */
- sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
-
- hisi_hba->debugfs_itct[dump_index].itct =
- devm_kmalloc(dev, sz, GFP_KERNEL);
- if (!hisi_hba->debugfs_itct[dump_index].itct)
- goto fail;
-
- return 0;
-fail:
- for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
- hisi_sas_debugfs_release(hisi_hba, i);
- return -ENOMEM;
-}
-
-static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba)
-{
- struct dentry *dir = debugfs_create_dir("phy_down_cnt",
- hisi_hba->debugfs_dir);
- char name[16];
- int phy_no;
-
- for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
- snprintf(name, 16, "%d", phy_no);
- debugfs_create_file(name, 0600, dir,
- &hisi_hba->phy[phy_no],
- &hisi_sas_debugfs_phy_down_cnt_ops);
- }
-}
-
-static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba)
-{
- struct dentry *ports_dentry;
- int phy_no;
-
- hisi_hba->debugfs_bist_dentry =
- debugfs_create_dir("bist", hisi_hba->debugfs_dir);
- debugfs_create_file("link_rate", 0600,
- hisi_hba->debugfs_bist_dentry, hisi_hba,
- &hisi_sas_debugfs_bist_linkrate_ops);
-
- debugfs_create_file("code_mode", 0600,
- hisi_hba->debugfs_bist_dentry, hisi_hba,
- &hisi_sas_debugfs_bist_code_mode_ops);
-
- debugfs_create_file("fixed_code", 0600,
- hisi_hba->debugfs_bist_dentry,
- &hisi_hba->debugfs_bist_fixed_code[0],
- &hisi_sas_debugfs_ops);
-
- debugfs_create_file("fixed_code_1", 0600,
- hisi_hba->debugfs_bist_dentry,
- &hisi_hba->debugfs_bist_fixed_code[1],
- &hisi_sas_debugfs_ops);
-
- debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry,
- hisi_hba, &hisi_sas_debugfs_bist_phy_ops);
-
- debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry,
- &hisi_hba->debugfs_bist_cnt);
-
- debugfs_create_file("loopback_mode", 0600,
- hisi_hba->debugfs_bist_dentry,
- hisi_hba, &hisi_sas_debugfs_bist_mode_ops);
-
- debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry,
- hisi_hba, &hisi_sas_debugfs_bist_enable_ops);
-
- ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry);
-
- for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
- struct dentry *port_dentry;
- struct dentry *ffe_dentry;
- char name[256];
- int i;
-
- snprintf(name, 256, "%d", phy_no);
- port_dentry = debugfs_create_dir(name, ports_dentry);
- ffe_dentry = debugfs_create_dir("ffe", port_dentry);
- for (i = 0; i < FFE_CFG_MAX; i++) {
- if (i == FFE_RESV)
- continue;
- debugfs_create_file(hisi_sas_debugfs_ffe_name[i].name,
- 0600, ffe_dentry,
- &hisi_hba->debugfs_bist_ffe[phy_no][i],
- &hisi_sas_debugfs_ops);
- }
- }
-
- hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS;
-}
-
-void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
-{
- struct device *dev = hisi_hba->dev;
- int i;
-
- hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
- hisi_sas_debugfs_dir);
- debugfs_create_file("trigger_dump", 0200,
- hisi_hba->debugfs_dir,
- hisi_hba,
- &hisi_sas_debugfs_trigger_dump_fops);
-
- /* create bist structures */
- hisi_sas_debugfs_bist_init(hisi_hba);
-
- hisi_hba->debugfs_dump_dentry =
- debugfs_create_dir("dump", hisi_hba->debugfs_dir);
-
- hisi_sas_debugfs_phy_down_cnt_init(hisi_hba);
-
- for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
- if (hisi_sas_debugfs_alloc(hisi_hba, i)) {
- debugfs_remove_recursive(hisi_hba->debugfs_dir);
- dev_dbg(dev, "failed to init debugfs!\n");
- break;
- }
- }
-}
-EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init);
-
-void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba)
-{
- debugfs_remove_recursive(hisi_hba->debugfs_dir);
-}
-EXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit);
-
int hisi_sas_remove(struct platform_device *pdev)
{
struct sas_ha_struct *sha = platform_get_drvdata(pdev);
@@ -4073,6 +2724,9 @@ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count);
module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444);
MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow");
+struct dentry *hisi_sas_debugfs_dir;
+EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dir);
+
static __init int hisi_sas_init(void)
{
hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 960de375ce69..7c12804b4e1d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -522,6 +522,8 @@ module_param(auto_affine_msi_experimental, bool, 0444);
MODULE_PARM_DESC(auto_affine_msi_experimental, "Enable auto-affinity of MSI IRQs as experimental:\n"
"default is off");
+static void debugfs_work_handler_v3_hw(struct work_struct *work);
+
static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
{
void __iomem *regs = hisi_hba->regs + off;
@@ -2409,8 +2411,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
DRV_NAME " phy", hisi_hba);
if (rc) {
dev_err(dev, "could not request phy interrupt, rc=%d\n", rc);
- rc = -ENOENT;
- goto free_irq_vectors;
+ return -ENOENT;
}
rc = devm_request_irq(dev, pci_irq_vector(pdev, 2),
@@ -2418,8 +2419,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
DRV_NAME " channel", hisi_hba);
if (rc) {
dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc);
- rc = -ENOENT;
- goto free_irq_vectors;
+ return -ENOENT;
}
rc = devm_request_irq(dev, pci_irq_vector(pdev, 11),
@@ -2427,8 +2427,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
DRV_NAME " fatal", hisi_hba);
if (rc) {
dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc);
- rc = -ENOENT;
- goto free_irq_vectors;
+ return -ENOENT;
}
if (hisi_sas_intr_conv)
@@ -2449,8 +2448,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
i, rc);
- rc = -ENOENT;
- goto free_irq_vectors;
+ return -ENOENT;
}
cq->irq_mask = pci_irq_get_affinity(pdev, i + BASE_VECTORS_V3_HW);
if (!cq->irq_mask) {
@@ -2460,10 +2458,6 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
}
return 0;
-
-free_irq_vectors:
- pci_free_irq_vectors(pdev);
- return rc;
}
static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
@@ -2766,6 +2760,19 @@ static struct device_attribute *host_attrs_v3_hw[] = {
NULL
};
+#define HISI_SAS_DEBUGFS_REG(x) {#x, x}
+
+struct hisi_sas_debugfs_reg_lu {
+ char *name;
+ int off;
+};
+
+struct hisi_sas_debugfs_reg {
+ const struct hisi_sas_debugfs_reg_lu *lu;
+ int count;
+ int base_off;
+};
+
static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = {
HISI_SAS_DEBUGFS_REG(PHY_CFG),
HISI_SAS_DEBUGFS_REG(HARD_PHY_LINKRATE),
@@ -2821,7 +2828,6 @@ static const struct hisi_sas_debugfs_reg debugfs_port_reg = {
.lu = debugfs_port_reg_lu,
.count = 0x100,
.base_off = PORT_BASE,
- .read_port_reg = hisi_sas_phy_read32,
};
static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = {
@@ -2894,7 +2900,6 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = {
static const struct hisi_sas_debugfs_reg debugfs_global_reg = {
.lu = debugfs_global_reg_lu,
.count = 0x800,
- .read_global_reg = hisi_sas_read32,
};
static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = {
@@ -2909,7 +2914,6 @@ static const struct hisi_sas_debugfs_reg debugfs_axi_reg = {
.lu = debugfs_axi_reg_lu,
.count = 0x61,
.base_off = AXI_MASTER_CFG_BASE,
- .read_global_reg = hisi_sas_read32,
};
static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = {
@@ -2927,7 +2931,6 @@ static const struct hisi_sas_debugfs_reg debugfs_ras_reg = {
.lu = debugfs_ras_reg_lu,
.count = 0x10,
.base_off = RAS_BASE,
- .read_global_reg = hisi_sas_read32,
};
static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
@@ -3147,7 +3150,6 @@ static struct scsi_host_template sht_v3_hw = {
};
static const struct hisi_sas_hw hisi_sas_v3_hw = {
- .hw_init = hisi_sas_v3_init,
.setup_itct = setup_itct_v3_hw,
.get_wideport_bitmap = get_wideport_bitmap_v3_hw,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
@@ -3170,14 +3172,6 @@ static const struct hisi_sas_hw hisi_sas_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,
- .debugfs_reg_array[DEBUGFS_GLOBAL] = &debugfs_global_reg,
- .debugfs_reg_array[DEBUGFS_AXI] = &debugfs_axi_reg,
- .debugfs_reg_array[DEBUGFS_RAS] = &debugfs_ras_reg,
- .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,
- .set_bist = debugfs_set_bist_v3_hw,
};
static struct Scsi_Host *
@@ -3195,7 +3189,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
hisi_hba = shost_priv(shost);
INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
- INIT_WORK(&hisi_hba->debugfs_work, hisi_sas_debugfs_work_handler);
+ INIT_WORK(&hisi_hba->debugfs_work, debugfs_work_handler_v3_hw);
hisi_hba->hw = &hisi_sas_v3_hw;
hisi_hba->pci_dev = pdev;
hisi_hba->dev = dev;
@@ -3223,6 +3217,1196 @@ err_out:
return NULL;
}
+static void debugfs_snapshot_cq_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int queue_entry_size = hisi_hba->hw->complete_hdr_size;
+ int dump_index = hisi_hba->debugfs_dump_index;
+ int i;
+
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
+ hisi_hba->complete_hdr[i],
+ HISI_SAS_QUEUE_SLOTS * queue_entry_size);
+}
+
+static void debugfs_snapshot_dq_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr);
+ int dump_index = hisi_hba->debugfs_dump_index;
+ int i;
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
+ int j;
+
+ debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
+ cmd_hdr = hisi_hba->cmd_hdr[i];
+
+ for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
+ memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j],
+ queue_entry_size);
+ }
+}
+
+static void debugfs_snapshot_port_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ const struct hisi_sas_debugfs_reg *port = &debugfs_port_reg;
+ int i, phy_cnt;
+ u32 offset;
+ u32 *databuf;
+
+ for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) {
+ databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
+ for (i = 0; i < port->count; i++, databuf++) {
+ offset = port->base_off + 4 * i;
+ *databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt,
+ offset);
+ }
+ }
+}
+
+static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
+ int i;
+
+ for (i = 0; i < debugfs_axi_reg.count; i++, databuf++)
+ *databuf = hisi_sas_read32(hisi_hba, 4 * i);
+}
+
+static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
+ const struct hisi_sas_debugfs_reg *axi = &debugfs_axi_reg;
+ int i;
+
+ for (i = 0; i < axi->count; i++, databuf++)
+ *databuf = hisi_sas_read32(hisi_hba, 4 * i + axi->base_off);
+}
+
+static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
+ const struct hisi_sas_debugfs_reg *ras = &debugfs_ras_reg;
+ int i;
+
+ for (i = 0; i < ras->count; i++, databuf++)
+ *databuf = hisi_sas_read32(hisi_hba, 4 * i + ras->base_off);
+}
+
+static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
+ void *databuf = hisi_hba->debugfs_itct[dump_index].itct;
+ struct hisi_sas_itct *itct;
+ int i;
+
+ read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_ITCT_CACHE, cachebuf);
+
+ 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 debugfs_snapshot_iost_reg_v3_hw(struct hisi_hba *hisi_hba)
+{
+ int dump_index = hisi_hba->debugfs_dump_index;
+ int max_command_entries = HISI_SAS_MAX_COMMANDS;
+ void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
+ void *databuf = hisi_hba->debugfs_iost[dump_index].iost;
+ struct hisi_sas_iost *iost;
+ int i;
+
+ read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_IOST_CACHE, cachebuf);
+
+ 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 const char *
+debugfs_to_reg_name_v3_hw(int off, int base_off,
+ const struct hisi_sas_debugfs_reg_lu *lu)
+{
+ for (; lu->name; lu++) {
+ if (off == lu->off - base_off)
+ return lu->name;
+ }
+
+ return NULL;
+}
+
+static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s,
+ const struct hisi_sas_debugfs_reg *reg)
+{
+ int i;
+
+ for (i = 0; i < reg->count; i++) {
+ int off = i * 4;
+ const char *name;
+
+ name = debugfs_to_reg_name_v3_hw(off, reg->base_off,
+ reg->lu);
+
+ if (name)
+ seq_printf(s, "0x%08x 0x%08x %s\n", off,
+ regs_val[i], name);
+ else
+ seq_printf(s, "0x%08x 0x%08x\n", off,
+ regs_val[i]);
+ }
+}
+
+static int debugfs_global_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_regs *global = s->private;
+
+ debugfs_print_reg_v3_hw(global->data, s,
+ &debugfs_global_reg);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_global_v3_hw);
+
+static int debugfs_axi_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_regs *axi = s->private;
+
+ debugfs_print_reg_v3_hw(axi->data, s,
+ &debugfs_axi_reg);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_axi_v3_hw);
+
+static int debugfs_ras_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_regs *ras = s->private;
+
+ debugfs_print_reg_v3_hw(ras->data, s,
+ &debugfs_ras_reg);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_ras_v3_hw);
+
+static int debugfs_port_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_port *port = s->private;
+ const struct hisi_sas_debugfs_reg *reg_port = &debugfs_port_reg;
+
+ debugfs_print_reg_v3_hw(port->data, s, reg_port);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_port_v3_hw);
+
+static void debugfs_show_row_64_v3_hw(struct seq_file *s, int index,
+ int sz, __le64 *ptr)
+{
+ int i;
+
+ /* completion header size not fixed per HW version */
+ seq_printf(s, "index %04d:\n\t", index);
+ for (i = 1; i <= sz / 8; i++, ptr++) {
+ seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr));
+ if (!(i % 2))
+ seq_puts(s, "\n\t");
+ }
+
+ seq_puts(s, "\n");
+}
+
+static void debugfs_show_row_32_v3_hw(struct seq_file *s, int index,
+ int sz, __le32 *ptr)
+{
+ int i;
+
+ /* completion header size not fixed per HW version */
+ seq_printf(s, "index %04d:\n\t", index);
+ for (i = 1; i <= sz / 4; i++, ptr++) {
+ seq_printf(s, " 0x%08x", le32_to_cpu(*ptr));
+ if (!(i % 4))
+ seq_puts(s, "\n\t");
+ }
+ seq_puts(s, "\n");
+}
+
+static void debugfs_cq_show_slot_v3_hw(struct seq_file *s, int slot,
+ struct hisi_sas_debugfs_cq *debugfs_cq)
+{
+ struct hisi_sas_cq *cq = debugfs_cq->cq;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ __le32 *complete_hdr = debugfs_cq->complete_hdr +
+ (hisi_hba->hw->complete_hdr_size * slot);
+
+ debugfs_show_row_32_v3_hw(s, slot,
+ hisi_hba->hw->complete_hdr_size,
+ complete_hdr);
+}
+
+static int debugfs_cq_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
+ int slot;
+
+ for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++)
+ debugfs_cq_show_slot_v3_hw(s, slot, debugfs_cq);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_cq_v3_hw);
+
+static void debugfs_dq_show_slot_v3_hw(struct seq_file *s, int slot,
+ void *dq_ptr)
+{
+ struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
+ void *cmd_queue = debugfs_dq->hdr;
+ __le32 *cmd_hdr = cmd_queue +
+ sizeof(struct hisi_sas_cmd_hdr) * slot;
+
+ debugfs_show_row_32_v3_hw(s, slot, sizeof(struct hisi_sas_cmd_hdr),
+ cmd_hdr);
+}
+
+static int debugfs_dq_v3_hw_show(struct seq_file *s, void *p)
+{
+ int slot;
+
+ for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++)
+ debugfs_dq_show_slot_v3_hw(s, slot, s->private);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_dq_v3_hw);
+
+static int debugfs_iost_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
+ struct hisi_sas_iost *iost = debugfs_iost->iost;
+ int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
+
+ for (i = 0; i < max_command_entries; i++, iost++) {
+ __le64 *data = &iost->qw0;
+
+ debugfs_show_row_64_v3_hw(s, i, sizeof(*iost), data);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_iost_v3_hw);
+
+static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
+ struct hisi_sas_iost_itct_cache *iost_cache =
+ debugfs_iost_cache->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;
+
+ debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, iost);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_iost_cache_v3_hw);
+
+static int debugfs_itct_v3_hw_show(struct seq_file *s, void *p)
+{
+ int i;
+ struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
+ struct hisi_sas_itct *itct = debugfs_itct->itct;
+
+ for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
+ __le64 *data = &itct->qw0;
+
+ debugfs_show_row_64_v3_hw(s, i, sizeof(*itct), data);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_itct_v3_hw);
+
+static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
+ struct hisi_sas_iost_itct_cache *itct_cache =
+ debugfs_itct_cache->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;
+
+ debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, itct);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(debugfs_itct_cache_v3_hw);
+
+static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)
+{
+ u64 *debugfs_timestamp;
+ int dump_index = hisi_hba->debugfs_dump_index;
+ struct dentry *dump_dentry;
+ struct dentry *dentry;
+ char name[256];
+ int p;
+ int c;
+ int d;
+
+ snprintf(name, 256, "%d", dump_index);
+
+ dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
+
+ debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
+
+ debugfs_create_u64("timestamp", 0400, dump_dentry,
+ debugfs_timestamp);
+
+ debugfs_create_file("global", 0400, dump_dentry,
+ &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
+ &debugfs_global_v3_hw_fops);
+
+ /* Create port dir and files */
+ dentry = debugfs_create_dir("port", dump_dentry);
+ for (p = 0; p < hisi_hba->n_phy; p++) {
+ snprintf(name, 256, "%d", p);
+
+ debugfs_create_file(name, 0400, dentry,
+ &hisi_hba->debugfs_port_reg[dump_index][p],
+ &debugfs_port_v3_hw_fops);
+ }
+
+ /* Create CQ dir and files */
+ dentry = debugfs_create_dir("cq", dump_dentry);
+ for (c = 0; c < hisi_hba->queue_count; c++) {
+ snprintf(name, 256, "%d", c);
+
+ debugfs_create_file(name, 0400, dentry,
+ &hisi_hba->debugfs_cq[dump_index][c],
+ &debugfs_cq_v3_hw_fops);
+ }
+
+ /* Create DQ dir and files */
+ dentry = debugfs_create_dir("dq", dump_dentry);
+ for (d = 0; d < hisi_hba->queue_count; d++) {
+ snprintf(name, 256, "%d", d);
+
+ debugfs_create_file(name, 0400, dentry,
+ &hisi_hba->debugfs_dq[dump_index][d],
+ &debugfs_dq_v3_hw_fops);
+ }
+
+ debugfs_create_file("iost", 0400, dump_dentry,
+ &hisi_hba->debugfs_iost[dump_index],
+ &debugfs_iost_v3_hw_fops);
+
+ debugfs_create_file("iost_cache", 0400, dump_dentry,
+ &hisi_hba->debugfs_iost_cache[dump_index],
+ &debugfs_iost_cache_v3_hw_fops);
+
+ debugfs_create_file("itct", 0400, dump_dentry,
+ &hisi_hba->debugfs_itct[dump_index],
+ &debugfs_itct_v3_hw_fops);
+
+ debugfs_create_file("itct_cache", 0400, dump_dentry,
+ &hisi_hba->debugfs_itct_cache[dump_index],
+ &debugfs_itct_cache_v3_hw_fops);
+
+ debugfs_create_file("axi", 0400, dump_dentry,
+ &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
+ &debugfs_axi_v3_hw_fops);
+
+ debugfs_create_file("ras", 0400, dump_dentry,
+ &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
+ &debugfs_ras_v3_hw_fops);
+}
+
+static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba)
+{
+ debugfs_snapshot_prepare_v3_hw(hisi_hba);
+
+ debugfs_snapshot_global_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_port_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_axi_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_ras_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_cq_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_dq_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_itct_reg_v3_hw(hisi_hba);
+ debugfs_snapshot_iost_reg_v3_hw(hisi_hba);
+
+ debugfs_create_files_v3_hw(hisi_hba);
+
+ debugfs_snapshot_restore_v3_hw(hisi_hba);
+}
+
+static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hisi_hba *hisi_hba = file->f_inode->i_private;
+ char buf[8];
+
+ if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
+ return -EFAULT;
+
+ if (count > 8)
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ if (buf[0] != '1')
+ return -EFAULT;
+
+ queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
+
+ return count;
+}
+
+static const struct file_operations debugfs_trigger_dump_v3_hw_fops = {
+ .write = &debugfs_trigger_dump_v3_hw_write,
+ .owner = THIS_MODULE,
+};
+
+enum {
+ HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0,
+ HISI_SAS_BIST_LOOPBACK_MODE_SERDES,
+ HISI_SAS_BIST_LOOPBACK_MODE_REMOTE,
+};
+
+static const struct {
+ int value;
+ char *name;
+} debugfs_loop_linkrate_v3_hw[] = {
+ { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
+ { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
+ { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
+ { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
+};
+
+static int debugfs_bist_linkrate_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_hba *hisi_hba = s->private;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) {
+ int match = (hisi_hba->debugfs_bist_linkrate ==
+ debugfs_loop_linkrate_v3_hw[i].value);
+
+ seq_printf(s, "%s%s%s ", match ? "[" : "",
+ debugfs_loop_linkrate_v3_hw[i].name,
+ match ? "]" : "");
+ }
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct hisi_hba *hisi_hba = m->private;
+ char kbuf[16] = {}, *pkbuf;
+ bool found = false;
+ int i;
+
+ if (hisi_hba->debugfs_bist_enable)
+ return -EPERM;
+
+ if (count >= sizeof(kbuf))
+ return -EOVERFLOW;
+
+ if (copy_from_user(kbuf, buf, count))
+ return -EINVAL;
+
+ pkbuf = strstrip(kbuf);
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) {
+ if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name,
+ pkbuf, 16)) {
+ hisi_hba->debugfs_bist_linkrate =
+ debugfs_loop_linkrate_v3_hw[i].value;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ return count;
+}
+
+static int debugfs_bist_linkrate_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_bist_linkrate_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_bist_linkrate_v3_hw_fops = {
+ .open = debugfs_bist_linkrate_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_bist_linkrate_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct {
+ int value;
+ char *name;
+} debugfs_loop_code_mode_v3_hw[] = {
+ { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" },
+ { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" },
+ { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" },
+ { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" },
+ { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" },
+ { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" },
+ { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" },
+ { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" },
+ { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" },
+ { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" },
+ { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" },
+ { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" },
+};
+
+static int debugfs_bist_code_mode_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_hba *hisi_hba = s->private;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) {
+ int match = (hisi_hba->debugfs_bist_code_mode ==
+ debugfs_loop_code_mode_v3_hw[i].value);
+
+ seq_printf(s, "%s%s%s ", match ? "[" : "",
+ debugfs_loop_code_mode_v3_hw[i].name,
+ match ? "]" : "");
+ }
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct hisi_hba *hisi_hba = m->private;
+ char kbuf[16] = {}, *pkbuf;
+ bool found = false;
+ int i;
+
+ if (hisi_hba->debugfs_bist_enable)
+ return -EPERM;
+
+ if (count >= sizeof(kbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, buf, count))
+ return -EOVERFLOW;
+
+ pkbuf = strstrip(kbuf);
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) {
+ if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name,
+ pkbuf, 16)) {
+ hisi_hba->debugfs_bist_code_mode =
+ debugfs_loop_code_mode_v3_hw[i].value;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ return count;
+}
+
+static int debugfs_bist_code_mode_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_bist_code_mode_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_bist_code_mode_v3_hw_fops = {
+ .open = debugfs_bist_code_mode_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_bist_code_mode_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t debugfs_bist_phy_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct hisi_hba *hisi_hba = m->private;
+ unsigned int phy_no;
+ int val;
+
+ if (hisi_hba->debugfs_bist_enable)
+ return -EPERM;
+
+ val = kstrtouint_from_user(buf, count, 0, &phy_no);
+ if (val)
+ return val;
+
+ if (phy_no >= hisi_hba->n_phy)
+ return -EINVAL;
+
+ hisi_hba->debugfs_bist_phy_no = phy_no;
+
+ return count;
+}
+
+static int debugfs_bist_phy_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_hba *hisi_hba = s->private;
+
+ seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no);
+
+ return 0;
+}
+
+static int debugfs_bist_phy_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_bist_phy_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_bist_phy_v3_hw_fops = {
+ .open = debugfs_bist_phy_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_bist_phy_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct {
+ int value;
+ char *name;
+} debugfs_loop_modes_v3_hw[] = {
+ { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
+ { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
+ { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
+};
+
+static int debugfs_bist_mode_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_hba *hisi_hba = s->private;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) {
+ int match = (hisi_hba->debugfs_bist_mode ==
+ debugfs_loop_modes_v3_hw[i].value);
+
+ seq_printf(s, "%s%s%s ", match ? "[" : "",
+ debugfs_loop_modes_v3_hw[i].name,
+ match ? "]" : "");
+ }
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct hisi_hba *hisi_hba = m->private;
+ char kbuf[16] = {}, *pkbuf;
+ bool found = false;
+ int i;
+
+ if (hisi_hba->debugfs_bist_enable)
+ return -EPERM;
+
+ if (count >= sizeof(kbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, buf, count))
+ return -EOVERFLOW;
+
+ pkbuf = strstrip(kbuf);
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) {
+ if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, 16)) {
+ hisi_hba->debugfs_bist_mode =
+ debugfs_loop_modes_v3_hw[i].value;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ return count;
+}
+
+static int debugfs_bist_mode_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_bist_mode_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_bist_mode_v3_hw_fops = {
+ .open = debugfs_bist_mode_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_bist_mode_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t debugfs_bist_enable_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct hisi_hba *hisi_hba = m->private;
+ unsigned int enable;
+ int val;
+
+ val = kstrtouint_from_user(buf, count, 0, &enable);
+ if (val)
+ return val;
+
+ if (enable > 1)
+ return -EINVAL;
+
+ if (enable == hisi_hba->debugfs_bist_enable)
+ return count;
+
+ val = debugfs_set_bist_v3_hw(hisi_hba, enable);
+ if (val < 0)
+ return val;
+
+ hisi_hba->debugfs_bist_enable = enable;
+
+ return count;
+}
+
+static int debugfs_bist_enable_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_hba *hisi_hba = s->private;
+
+ seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable);
+
+ return 0;
+}
+
+static int debugfs_bist_enable_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_bist_enable_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_bist_enable_v3_hw_fops = {
+ .open = debugfs_bist_enable_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_bist_enable_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct {
+ char *name;
+} debugfs_ffe_name_v3_hw[FFE_CFG_MAX] = {
+ { "SAS_1_5_GBPS" },
+ { "SAS_3_0_GBPS" },
+ { "SAS_6_0_GBPS" },
+ { "SAS_12_0_GBPS" },
+ { "FFE_RESV" },
+ { "SATA_1_5_GBPS" },
+ { "SATA_3_0_GBPS" },
+ { "SATA_6_0_GBPS" },
+};
+
+static ssize_t debugfs_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ u32 *val = m->private;
+ int res;
+
+ res = kstrtouint_from_user(buf, count, 0, val);
+ if (res)
+ return res;
+
+ return count;
+}
+
+static int debugfs_v3_hw_show(struct seq_file *s, void *p)
+{
+ u32 *val = s->private;
+
+ seq_printf(s, "0x%x\n", *val);
+
+ return 0;
+}
+
+static int debugfs_v3_hw_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, debugfs_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_v3_hw_fops = {
+ .open = debugfs_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t debugfs_phy_down_cnt_v3_hw_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = filp->private_data;
+ struct hisi_sas_phy *phy = s->private;
+ unsigned int set_val;
+ int res;
+
+ res = kstrtouint_from_user(buf, count, 0, &set_val);
+ if (res)
+ return res;
+
+ if (set_val > 0)
+ return -EINVAL;
+
+ atomic_set(&phy->down_cnt, 0);
+
+ return count;
+}
+
+static int debugfs_phy_down_cnt_v3_hw_show(struct seq_file *s, void *p)
+{
+ struct hisi_sas_phy *phy = s->private;
+
+ seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
+
+ return 0;
+}
+
+static int debugfs_phy_down_cnt_v3_hw_open(struct inode *inode,
+ struct file *filp)
+{
+ return single_open(filp, debugfs_phy_down_cnt_v3_hw_show,
+ inode->i_private);
+}
+
+static const struct file_operations debugfs_phy_down_cnt_v3_hw_fops = {
+ .open = debugfs_phy_down_cnt_v3_hw_open,
+ .read = seq_read,
+ .write = debugfs_phy_down_cnt_v3_hw_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void debugfs_work_handler_v3_hw(struct work_struct *work)
+{
+ struct hisi_hba *hisi_hba =
+ container_of(work, struct hisi_hba, debugfs_work);
+ int debugfs_dump_index = hisi_hba->debugfs_dump_index;
+ struct device *dev = hisi_hba->dev;
+ u64 timestamp = local_clock();
+
+ if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
+ dev_warn(dev, "dump count exceeded!\n");
+ return;
+ }
+
+ do_div(timestamp, NSEC_PER_MSEC);
+ hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
+
+ debugfs_snapshot_regs_v3_hw(hisi_hba);
+ hisi_hba->debugfs_dump_index++;
+}
+
+static void debugfs_release_v3_hw(struct hisi_hba *hisi_hba, int dump_index)
+{
+ struct device *dev = hisi_hba->dev;
+ int i;
+
+ devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
+ devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
+ devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
+ devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
+
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
+
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ devm_kfree(dev,
+ hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
+
+ for (i = 0; i < DEBUGFS_REGS_NUM; i++)
+ devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
+}
+
+static const struct hisi_sas_debugfs_reg *debugfs_reg_array_v3_hw[DEBUGFS_REGS_NUM] = {
+ [DEBUGFS_GLOBAL] = &debugfs_global_reg,
+ [DEBUGFS_AXI] = &debugfs_axi_reg,
+ [DEBUGFS_RAS] = &debugfs_ras_reg,
+};
+
+static int debugfs_alloc_v3_hw(struct hisi_hba *hisi_hba, int dump_index)
+{
+ const struct hisi_sas_hw *hw = hisi_hba->hw;
+ struct device *dev = hisi_hba->dev;
+ int p, c, d, r, i;
+ size_t sz;
+
+ for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
+ struct hisi_sas_debugfs_regs *regs =
+ &hisi_hba->debugfs_regs[dump_index][r];
+
+ sz = debugfs_reg_array_v3_hw[r]->count * 4;
+ regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!regs->data)
+ goto fail;
+ regs->hisi_hba = hisi_hba;
+ }
+
+ sz = debugfs_port_reg.count * 4;
+ for (p = 0; p < hisi_hba->n_phy; p++) {
+ struct hisi_sas_debugfs_port *port =
+ &hisi_hba->debugfs_port_reg[dump_index][p];
+
+ port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!port->data)
+ goto fail;
+ port->phy = &hisi_hba->phy[p];
+ }
+
+ sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ for (c = 0; c < hisi_hba->queue_count; c++) {
+ struct hisi_sas_debugfs_cq *cq =
+ &hisi_hba->debugfs_cq[dump_index][c];
+
+ cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!cq->complete_hdr)
+ goto fail;
+ cq->cq = &hisi_hba->cq[c];
+ }
+
+ sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ for (d = 0; d < hisi_hba->queue_count; d++) {
+ struct hisi_sas_debugfs_dq *dq =
+ &hisi_hba->debugfs_dq[dump_index][d];
+
+ dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!dq->hdr)
+ goto fail;
+ dq->dq = &hisi_hba->dq[d];
+ }
+
+ sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
+
+ hisi_hba->debugfs_iost[dump_index].iost =
+ devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!hisi_hba->debugfs_iost[dump_index].iost)
+ goto fail;
+
+ sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+ sizeof(struct hisi_sas_iost_itct_cache);
+
+ hisi_hba->debugfs_iost_cache[dump_index].cache =
+ devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
+ goto fail;
+
+ sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+ sizeof(struct hisi_sas_iost_itct_cache);
+
+ hisi_hba->debugfs_itct_cache[dump_index].cache =
+ devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
+ goto fail;
+
+ /* New memory allocation must be locate before itct */
+ sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+
+ hisi_hba->debugfs_itct[dump_index].itct =
+ devm_kmalloc(dev, sz, GFP_KERNEL);
+ if (!hisi_hba->debugfs_itct[dump_index].itct)
+ goto fail;
+
+ return 0;
+fail:
+ for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
+ debugfs_release_v3_hw(hisi_hba, i);
+ return -ENOMEM;
+}
+
+static void debugfs_phy_down_cnt_init_v3_hw(struct hisi_hba *hisi_hba)
+{
+ struct dentry *dir = debugfs_create_dir("phy_down_cnt",
+ hisi_hba->debugfs_dir);
+ char name[16];
+ int phy_no;
+
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ snprintf(name, 16, "%d", phy_no);
+ debugfs_create_file(name, 0600, dir,
+ &hisi_hba->phy[phy_no],
+ &debugfs_phy_down_cnt_v3_hw_fops);
+ }
+}
+
+static void debugfs_bist_init_v3_hw(struct hisi_hba *hisi_hba)
+{
+ struct dentry *ports_dentry;
+ int phy_no;
+
+ hisi_hba->debugfs_bist_dentry =
+ debugfs_create_dir("bist", hisi_hba->debugfs_dir);
+ debugfs_create_file("link_rate", 0600,
+ hisi_hba->debugfs_bist_dentry, hisi_hba,
+ &debugfs_bist_linkrate_v3_hw_fops);
+
+ debugfs_create_file("code_mode", 0600,
+ hisi_hba->debugfs_bist_dentry, hisi_hba,
+ &debugfs_bist_code_mode_v3_hw_fops);
+
+ debugfs_create_file("fixed_code", 0600,
+ hisi_hba->debugfs_bist_dentry,
+ &hisi_hba->debugfs_bist_fixed_code[0],
+ &debugfs_v3_hw_fops);
+
+ debugfs_create_file("fixed_code_1", 0600,
+ hisi_hba->debugfs_bist_dentry,
+ &hisi_hba->debugfs_bist_fixed_code[1],
+ &debugfs_v3_hw_fops);
+
+ debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry,
+ hisi_hba, &debugfs_bist_phy_v3_hw_fops);
+
+ debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry,
+ &hisi_hba->debugfs_bist_cnt);
+
+ debugfs_create_file("loopback_mode", 0600,
+ hisi_hba->debugfs_bist_dentry,
+ hisi_hba, &debugfs_bist_mode_v3_hw_fops);
+
+ debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry,
+ hisi_hba, &debugfs_bist_enable_v3_hw_fops);
+
+ ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry);
+
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ struct dentry *port_dentry;
+ struct dentry *ffe_dentry;
+ char name[256];
+ int i;
+
+ snprintf(name, 256, "%d", phy_no);
+ port_dentry = debugfs_create_dir(name, ports_dentry);
+ ffe_dentry = debugfs_create_dir("ffe", port_dentry);
+ for (i = 0; i < FFE_CFG_MAX; i++) {
+ if (i == FFE_RESV)
+ continue;
+ debugfs_create_file(debugfs_ffe_name_v3_hw[i].name,
+ 0600, ffe_dentry,
+ &hisi_hba->debugfs_bist_ffe[phy_no][i],
+ &debugfs_v3_hw_fops);
+ }
+ }
+
+ hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS;
+}
+
+static void debugfs_init_v3_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = hisi_hba->dev;
+ int i;
+
+ hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
+ hisi_sas_debugfs_dir);
+ debugfs_create_file("trigger_dump", 0200,
+ hisi_hba->debugfs_dir,
+ hisi_hba,
+ &debugfs_trigger_dump_v3_hw_fops);
+
+ /* create bist structures */
+ debugfs_bist_init_v3_hw(hisi_hba);
+
+ hisi_hba->debugfs_dump_dentry =
+ debugfs_create_dir("dump", hisi_hba->debugfs_dir);
+
+ debugfs_phy_down_cnt_init_v3_hw(hisi_hba);
+
+ for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
+ if (debugfs_alloc_v3_hw(hisi_hba, i)) {
+ debugfs_remove_recursive(hisi_hba->debugfs_dir);
+ dev_dbg(dev, "failed to init debugfs!\n");
+ break;
+ }
+ }
+}
+
+static void debugfs_exit_v3_hw(struct hisi_hba *hisi_hba)
+{
+ debugfs_remove_recursive(hisi_hba->debugfs_dir);
+}
+
static int
hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -3313,21 +4497,21 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
if (hisi_sas_debugfs_enable)
- hisi_sas_debugfs_init(hisi_hba);
+ debugfs_init_v3_hw(hisi_hba);
rc = interrupt_preinit_v3_hw(hisi_hba);
if (rc)
- goto err_out_ha;
+ goto err_out_debugfs;
dev_err(dev, "%d hw queues\n", shost->nr_hw_queues);
rc = scsi_add_host(shost, dev);
if (rc)
- goto err_out_ha;
+ goto err_out_free_irq_vectors;
rc = sas_register_ha(sha);
if (rc)
goto err_out_register_ha;
- rc = hisi_hba->hw->hw_init(hisi_hba);
+ rc = hisi_sas_v3_init(hisi_hba);
if (rc)
goto err_out_register_ha;
@@ -3348,8 +4532,12 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_out_register_ha:
scsi_remove_host(shost);
+err_out_free_irq_vectors:
+ pci_free_irq_vectors(pdev);
+err_out_debugfs:
+ debugfs_exit_v3_hw(hisi_hba);
err_out_ha:
- hisi_sas_debugfs_exit(hisi_hba);
+ hisi_sas_free(hisi_hba);
scsi_host_put(shost);
err_out_regions:
pci_release_regions(pdev);
@@ -3394,7 +4582,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
hisi_sas_free(hisi_hba);
- hisi_sas_debugfs_exit(hisi_hba);
+ debugfs_exit_v3_hw(hisi_hba);
scsi_host_put(shost);
}
@@ -3445,7 +4633,6 @@ static int _suspend_v3_hw(struct device *device)
struct hisi_hba *hisi_hba = sha->lldd_ha;
struct device *dev = hisi_hba->dev;
struct Scsi_Host *shost = hisi_hba->shost;
- pci_power_t device_state;
int rc;
if (!pdev->pm_cap) {
@@ -3471,12 +4658,7 @@ static int _suspend_v3_hw(struct device *device)
hisi_sas_init_mem(hisi_hba);
- device_state = pci_choose_state(pdev, PMSG_SUSPEND);
- dev_warn(dev, "entering operating state [D%d]\n",
- device_state);
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, device_state);
+ dev_warn(dev, "entering suspend state\n");
hisi_sas_release_tasks(hisi_hba);
@@ -3496,16 +4678,7 @@ static int _resume_v3_hw(struct device *device)
dev_warn(dev, "resuming from operating state [D%d]\n",
device_state);
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, PCI_D0, 0);
- pci_restore_state(pdev);
- rc = pci_enable_device(pdev);
- if (rc) {
- dev_err(dev, "enable device failed during resume (%d)\n", rc);
- return rc;
- }
- pci_set_master(pdev);
scsi_unblock_requests(shost);
clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
@@ -3513,17 +4686,16 @@ static int _resume_v3_hw(struct device *device)
rc = hw_init_v3_hw(hisi_hba);
if (rc) {
scsi_remove_host(shost);
- pci_disable_device(pdev);
return rc;
}
- hisi_hba->hw->phys_init(hisi_hba);
+ phys_init_v3_hw(hisi_hba);
sas_resume_ha(sha);
clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
return 0;
}
-static int suspend_v3_hw(struct device *device)
+static int __maybe_unused suspend_v3_hw(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
@@ -3539,7 +4711,7 @@ static int suspend_v3_hw(struct device *device)
return rc;
}
-static int resume_v3_hw(struct device *device)
+static int __maybe_unused resume_v3_hw(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
@@ -3562,21 +4734,10 @@ static const struct pci_error_handlers hisi_sas_err_handler = {
.reset_done = hisi_sas_reset_done_v3_hw,
};
-static int runtime_suspend_v3_hw(struct device *dev)
-{
- return suspend_v3_hw(dev);
-}
-
-static int runtime_resume_v3_hw(struct device *dev)
-{
- return resume_v3_hw(dev);
-}
-
-static const struct dev_pm_ops hisi_sas_v3_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(suspend_v3_hw, resume_v3_hw)
- SET_RUNTIME_PM_OPS(runtime_suspend_v3_hw,
- runtime_resume_v3_hw, NULL)
-};
+static UNIVERSAL_DEV_PM_OPS(hisi_sas_v3_pm_ops,
+ suspend_v3_hw,
+ resume_v3_hw,
+ NULL);
static struct pci_driver sas_v3_pci_driver = {
.name = DRV_NAME,