162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic iSCSI Offload Driver
462306a36Sopenharmony_ci * Copyright (c) 2016 Cavium Inc.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "qedi.h"
862306a36Sopenharmony_ci#include "qedi_dbg.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/uaccess.h>
1162306a36Sopenharmony_ci#include <linux/debugfs.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciint qedi_do_not_recover;
1562306a36Sopenharmony_cistatic struct dentry *qedi_dbg_root;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_civoid
1862306a36Sopenharmony_ciqedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
1962306a36Sopenharmony_ci		   const struct qedi_debugfs_ops *dops,
2062306a36Sopenharmony_ci		   const struct file_operations *fops)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	char host_dirname[32];
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	sprintf(host_dirname, "host%u", qedi->host_no);
2562306a36Sopenharmony_ci	qedi->bdf_dentry = debugfs_create_dir(host_dirname, qedi_dbg_root);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	while (dops) {
2862306a36Sopenharmony_ci		if (!(dops->name))
2962306a36Sopenharmony_ci			break;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci		debugfs_create_file(dops->name, 0600, qedi->bdf_dentry, qedi,
3262306a36Sopenharmony_ci				    fops);
3362306a36Sopenharmony_ci		dops++;
3462306a36Sopenharmony_ci		fops++;
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_civoid
3962306a36Sopenharmony_ciqedi_dbg_host_exit(struct qedi_dbg_ctx *qedi)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	debugfs_remove_recursive(qedi->bdf_dentry);
4262306a36Sopenharmony_ci	qedi->bdf_dentry = NULL;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid
4662306a36Sopenharmony_ciqedi_dbg_init(char *drv_name)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	qedi_dbg_root = debugfs_create_dir(drv_name, NULL);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid
5262306a36Sopenharmony_ciqedi_dbg_exit(void)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	debugfs_remove_recursive(qedi_dbg_root);
5562306a36Sopenharmony_ci	qedi_dbg_root = NULL;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic ssize_t
5962306a36Sopenharmony_ciqedi_dbg_do_not_recover_enable(struct qedi_dbg_ctx *qedi_dbg)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (!qedi_do_not_recover)
6262306a36Sopenharmony_ci		qedi_do_not_recover = 1;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
6562306a36Sopenharmony_ci		  qedi_do_not_recover);
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic ssize_t
7062306a36Sopenharmony_ciqedi_dbg_do_not_recover_disable(struct qedi_dbg_ctx *qedi_dbg)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	if (qedi_do_not_recover)
7362306a36Sopenharmony_ci		qedi_do_not_recover = 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
7662306a36Sopenharmony_ci		  qedi_do_not_recover);
7762306a36Sopenharmony_ci	return 0;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = {
8162306a36Sopenharmony_ci	{ "enable", qedi_dbg_do_not_recover_enable },
8262306a36Sopenharmony_ci	{ "disable", qedi_dbg_do_not_recover_disable },
8362306a36Sopenharmony_ci	{ NULL, NULL }
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciconst struct qedi_debugfs_ops qedi_debugfs_ops[] = {
8762306a36Sopenharmony_ci	{ "gbl_ctx", NULL },
8862306a36Sopenharmony_ci	{ "do_not_recover", qedi_dbg_do_not_recover_ops},
8962306a36Sopenharmony_ci	{ "io_trace", NULL },
9062306a36Sopenharmony_ci	{ NULL, NULL }
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic ssize_t
9462306a36Sopenharmony_ciqedi_dbg_do_not_recover_cmd_write(struct file *filp, const char __user *buffer,
9562306a36Sopenharmony_ci				  size_t count, loff_t *ppos)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	size_t cnt = 0;
9862306a36Sopenharmony_ci	struct qedi_dbg_ctx *qedi_dbg =
9962306a36Sopenharmony_ci			(struct qedi_dbg_ctx *)filp->private_data;
10062306a36Sopenharmony_ci	struct qedi_list_of_funcs *lof = qedi_dbg_do_not_recover_ops;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (*ppos)
10362306a36Sopenharmony_ci		return 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	while (lof) {
10662306a36Sopenharmony_ci		if (!(lof->oper_str))
10762306a36Sopenharmony_ci			break;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		if (!strncmp(lof->oper_str, buffer, strlen(lof->oper_str))) {
11062306a36Sopenharmony_ci			cnt = lof->oper_func(qedi_dbg);
11162306a36Sopenharmony_ci			break;
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		lof++;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	return (count - cnt);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic ssize_t
12062306a36Sopenharmony_ciqedi_dbg_do_not_recover_cmd_read(struct file *filp, char __user *buffer,
12162306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	size_t cnt = 0;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (*ppos)
12662306a36Sopenharmony_ci		return 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	cnt = sprintf(buffer, "do_not_recover=%d\n", qedi_do_not_recover);
12962306a36Sopenharmony_ci	cnt = min_t(int, count, cnt - *ppos);
13062306a36Sopenharmony_ci	*ppos += cnt;
13162306a36Sopenharmony_ci	return cnt;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int
13562306a36Sopenharmony_ciqedi_gbl_ctx_show(struct seq_file *s, void *unused)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct qedi_fastpath *fp = NULL;
13862306a36Sopenharmony_ci	struct qed_sb_info *sb_info = NULL;
13962306a36Sopenharmony_ci	struct status_block *sb = NULL;
14062306a36Sopenharmony_ci	struct global_queue *que = NULL;
14162306a36Sopenharmony_ci	int id;
14262306a36Sopenharmony_ci	u16 prod_idx;
14362306a36Sopenharmony_ci	struct qedi_ctx *qedi = s->private;
14462306a36Sopenharmony_ci	unsigned long flags;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	seq_puts(s, " DUMP CQ CONTEXT:\n");
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
14962306a36Sopenharmony_ci		spin_lock_irqsave(&qedi->hba_lock, flags);
15062306a36Sopenharmony_ci		seq_printf(s, "=========FAST CQ PATH [%d] ==========\n", id);
15162306a36Sopenharmony_ci		fp = &qedi->fp_array[id];
15262306a36Sopenharmony_ci		sb_info = fp->sb_info;
15362306a36Sopenharmony_ci		sb = sb_info->sb_virt;
15462306a36Sopenharmony_ci		prod_idx = (sb->pi_array[QEDI_PROTO_CQ_PROD_IDX] &
15562306a36Sopenharmony_ci			    STATUS_BLOCK_PROD_INDEX_MASK);
15662306a36Sopenharmony_ci		seq_printf(s, "SB PROD IDX: %d\n", prod_idx);
15762306a36Sopenharmony_ci		que = qedi->global_queues[fp->sb_id];
15862306a36Sopenharmony_ci		seq_printf(s, "DRV CONS IDX: %d\n", que->cq_cons_idx);
15962306a36Sopenharmony_ci		seq_printf(s, "CQ complete host memory: %d\n", fp->sb_id);
16062306a36Sopenharmony_ci		seq_puts(s, "=========== END ==================\n\n\n");
16162306a36Sopenharmony_ci		spin_unlock_irqrestore(&qedi->hba_lock, flags);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int
16762306a36Sopenharmony_ciqedi_dbg_gbl_ctx_open(struct inode *inode, struct file *file)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
17062306a36Sopenharmony_ci	struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
17162306a36Sopenharmony_ci					     dbg_ctx);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return single_open(file, qedi_gbl_ctx_show, qedi);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int
17762306a36Sopenharmony_ciqedi_io_trace_show(struct seq_file *s, void *unused)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int id, idx = 0;
18062306a36Sopenharmony_ci	struct qedi_ctx *qedi = s->private;
18162306a36Sopenharmony_ci	struct qedi_io_log *io_log;
18262306a36Sopenharmony_ci	unsigned long flags;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	seq_puts(s, " DUMP IO LOGS:\n");
18562306a36Sopenharmony_ci	spin_lock_irqsave(&qedi->io_trace_lock, flags);
18662306a36Sopenharmony_ci	idx = qedi->io_trace_idx;
18762306a36Sopenharmony_ci	for (id = 0; id < QEDI_IO_TRACE_SIZE; id++) {
18862306a36Sopenharmony_ci		io_log = &qedi->io_trace_buf[idx];
18962306a36Sopenharmony_ci		seq_printf(s, "iodir-%d:", io_log->direction);
19062306a36Sopenharmony_ci		seq_printf(s, "tid-0x%x:", io_log->task_id);
19162306a36Sopenharmony_ci		seq_printf(s, "cid-0x%x:", io_log->cid);
19262306a36Sopenharmony_ci		seq_printf(s, "lun-%d:", io_log->lun);
19362306a36Sopenharmony_ci		seq_printf(s, "op-0x%02x:", io_log->op);
19462306a36Sopenharmony_ci		seq_printf(s, "0x%02x%02x%02x%02x:", io_log->lba[0],
19562306a36Sopenharmony_ci			   io_log->lba[1], io_log->lba[2], io_log->lba[3]);
19662306a36Sopenharmony_ci		seq_printf(s, "buflen-%d:", io_log->bufflen);
19762306a36Sopenharmony_ci		seq_printf(s, "sgcnt-%d:", io_log->sg_count);
19862306a36Sopenharmony_ci		seq_printf(s, "res-0x%08x:", io_log->result);
19962306a36Sopenharmony_ci		seq_printf(s, "jif-%lu:", io_log->jiffies);
20062306a36Sopenharmony_ci		seq_printf(s, "blk_req_cpu-%d:", io_log->blk_req_cpu);
20162306a36Sopenharmony_ci		seq_printf(s, "req_cpu-%d:", io_log->req_cpu);
20262306a36Sopenharmony_ci		seq_printf(s, "intr_cpu-%d:", io_log->intr_cpu);
20362306a36Sopenharmony_ci		seq_printf(s, "blk_rsp_cpu-%d\n", io_log->blk_rsp_cpu);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		idx++;
20662306a36Sopenharmony_ci		if (idx == QEDI_IO_TRACE_SIZE)
20762306a36Sopenharmony_ci			idx = 0;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	spin_unlock_irqrestore(&qedi->io_trace_lock, flags);
21062306a36Sopenharmony_ci	return 0;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int
21462306a36Sopenharmony_ciqedi_dbg_io_trace_open(struct inode *inode, struct file *file)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
21762306a36Sopenharmony_ci	struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
21862306a36Sopenharmony_ci					     dbg_ctx);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return single_open(file, qedi_io_trace_show, qedi);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciconst struct file_operations qedi_dbg_fops[] = {
22462306a36Sopenharmony_ci	qedi_dbg_fileops_seq(qedi, gbl_ctx),
22562306a36Sopenharmony_ci	qedi_dbg_fileops(qedi, do_not_recover),
22662306a36Sopenharmony_ci	qedi_dbg_fileops_seq(qedi, io_trace),
22762306a36Sopenharmony_ci	{ },
22862306a36Sopenharmony_ci};
229