summaryrefslogtreecommitdiff
path: root/drivers/scsi/qedf/qedf_debugfs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-03-03 21:36:56 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-03-03 21:36:56 -0800
commita3b4924b027f9a4b95ce89a914c1e0459e76f18a (patch)
tree49f77a75c4fb2698f1251e42e7e893ed366f3abe /drivers/scsi/qedf/qedf_debugfs.c
parent0b94da8dfc26ec2eb3e6640726e434abf8c53e49 (diff)
parent42a70abddd90374518057e989f5b7289b7b535d8 (diff)
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull more SCSI updates from James Bottomley: "This is the set of stuff that didn't quite make the initial pull and a set of fixes for stuff which did. The new stuff is basically lpfc (nvme), qedi and aacraid. The fixes cover a lot of previously submitted stuff, the most important of which probably covers some of the failing irq vectors allocation and other fallout from having the SCSI command allocated as part of the block allocation functions" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (59 commits) scsi: qedi: Fix memory leak in tmf response processing. scsi: aacraid: remove redundant zero check on ret scsi: lpfc: use proper format string for dma_addr_t scsi: lpfc: use div_u64 for 64-bit division scsi: mac_scsi: Fix MAC_SCSI=m option when SCSI=m scsi: cciss: correct check map error. scsi: qla2xxx: fix spelling mistake: "seperator" -> "separator" scsi: aacraid: Fixed expander hotplug for SMART family scsi: mpt3sas: switch to pci_alloc_irq_vectors scsi: qedf: fixup compilation warning about atomic_t usage scsi: remove scsi_execute_req_flags scsi: merge __scsi_execute into scsi_execute scsi: simplify scsi_execute_req_flags scsi: make the sense header argument to scsi_test_unit_ready mandatory scsi: sd: improve TUR handling in sd_check_events scsi: always zero sshdr in scsi_normalize_sense scsi: scsi_dh_emc: return success in clariion_std_inquiry() scsi: fix memory leak of sdpk on when gd fails to allocate scsi: sd: make sd_devt_release() static scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework. ...
Diffstat (limited to 'drivers/scsi/qedf/qedf_debugfs.c')
-rw-r--r--drivers/scsi/qedf/qedf_debugfs.c460
1 files changed, 460 insertions, 0 deletions
diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c
new file mode 100644
index 000000000000..cb08b625c594
--- /dev/null
+++ b/drivers/scsi/qedf/qedf_debugfs.c
@@ -0,0 +1,460 @@
+/*
+ * QLogic FCoE Offload Driver
+ * Copyright (c) 2016 QLogic Corporation
+ *
+ * This software is available under the terms of the GNU General Public License
+ * (GPL) Version 2, available from the file COPYING in the main directory of
+ * this source tree.
+ */
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "qedf.h"
+#include "qedf_dbg.h"
+
+static struct dentry *qedf_dbg_root;
+
+/**
+ * qedf_dbg_host_init - setup the debugfs file for the pf
+ * @pf: the pf that is starting up
+ **/
+void
+qedf_dbg_host_init(struct qedf_dbg_ctx *qedf,
+ struct qedf_debugfs_ops *dops,
+ struct file_operations *fops)
+{
+ char host_dirname[32];
+ struct dentry *file_dentry = NULL;
+
+ QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "Creating debugfs host node\n");
+ /* create pf dir */
+ sprintf(host_dirname, "host%u", qedf->host_no);
+ qedf->bdf_dentry = debugfs_create_dir(host_dirname, qedf_dbg_root);
+ if (!qedf->bdf_dentry)
+ return;
+
+ /* create debugfs files */
+ while (dops) {
+ if (!(dops->name))
+ break;
+
+ file_dentry = debugfs_create_file(dops->name, 0600,
+ qedf->bdf_dentry, qedf,
+ fops);
+ if (!file_dentry) {
+ QEDF_INFO(qedf, QEDF_LOG_DEBUGFS,
+ "Debugfs entry %s creation failed\n",
+ dops->name);
+ debugfs_remove_recursive(qedf->bdf_dentry);
+ return;
+ }
+ dops++;
+ fops++;
+ }
+}
+
+/**
+ * qedf_dbg_host_exit - clear out the pf's debugfs entries
+ * @pf: the pf that is stopping
+ **/
+void
+qedf_dbg_host_exit(struct qedf_dbg_ctx *qedf)
+{
+ QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "Destroying debugfs host "
+ "entry\n");
+ /* remove debugfs entries of this PF */
+ debugfs_remove_recursive(qedf->bdf_dentry);
+ qedf->bdf_dentry = NULL;
+}
+
+/**
+ * qedf_dbg_init - start up debugfs for the driver
+ **/
+void
+qedf_dbg_init(char *drv_name)
+{
+ QEDF_INFO(NULL, QEDF_LOG_DEBUGFS, "Creating debugfs root node\n");
+
+ /* create qed dir in root of debugfs. NULL means debugfs root */
+ qedf_dbg_root = debugfs_create_dir(drv_name, NULL);
+ if (!qedf_dbg_root)
+ QEDF_INFO(NULL, QEDF_LOG_DEBUGFS, "Init of debugfs "
+ "failed\n");
+}
+
+/**
+ * qedf_dbg_exit - clean out the driver's debugfs entries
+ **/
+void
+qedf_dbg_exit(void)
+{
+ QEDF_INFO(NULL, QEDF_LOG_DEBUGFS, "Destroying debugfs root "
+ "entry\n");
+
+ /* remove qed dir in root of debugfs */
+ debugfs_remove_recursive(qedf_dbg_root);
+ qedf_dbg_root = NULL;
+}
+
+struct qedf_debugfs_ops qedf_debugfs_ops[] = {
+ { "fp_int", NULL },
+ { "io_trace", NULL },
+ { "debug", NULL },
+ { "stop_io_on_error", NULL},
+ { "driver_stats", NULL},
+ { "clear_stats", NULL},
+ { "offload_stats", NULL},
+ /* This must be last */
+ { NULL, NULL }
+};
+
+DECLARE_PER_CPU(struct qedf_percpu_iothread_s, qedf_percpu_iothreads);
+
+static ssize_t
+qedf_dbg_fp_int_cmd_read(struct file *filp, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ size_t cnt = 0;
+ int id;
+ struct qedf_fastpath *fp = NULL;
+ struct qedf_dbg_ctx *qedf_dbg =
+ (struct qedf_dbg_ctx *)filp->private_data;
+ struct qedf_ctx *qedf = container_of(qedf_dbg,
+ struct qedf_ctx, dbg_ctx);
+
+ QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n");
+
+ cnt = sprintf(buffer, "\nFastpath I/O completions\n\n");
+
+ for (id = 0; id < qedf->num_queues; id++) {
+ fp = &(qedf->fp_array[id]);
+ if (fp->sb_id == QEDF_SB_ID_NULL)
+ continue;
+ cnt += sprintf((buffer + cnt), "#%d: %lu\n", id,
+ fp->completions);
+ }
+
+ cnt = min_t(int, count, cnt - *ppos);
+ *ppos += cnt;
+ return cnt;
+}
+
+static ssize_t
+qedf_dbg_fp_int_cmd_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ if (!count || *ppos)
+ return 0;
+
+ return count;
+}
+
+static ssize_t
+qedf_dbg_debug_cmd_read(struct file *filp, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ int cnt;
+ struct qedf_dbg_ctx *qedf =
+ (struct qedf_dbg_ctx *)filp->private_data;
+
+ QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "entered\n");
+ cnt = sprintf(buffer, "debug mask = 0x%x\n", qedf_debug);
+
+ cnt = min_t(int, count, cnt - *ppos);
+ *ppos += cnt;
+ return cnt;
+}
+
+static ssize_t
+qedf_dbg_debug_cmd_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ uint32_t val;
+ void *kern_buf;
+ int rval;
+ struct qedf_dbg_ctx *qedf =
+ (struct qedf_dbg_ctx *)filp->private_data;
+
+ if (!count || *ppos)
+ return 0;
+
+ kern_buf = memdup_user(buffer, count);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
+
+ rval = kstrtouint(kern_buf, 10, &val);
+ kfree(kern_buf);
+ if (rval)
+ return rval;
+
+ if (val == 1)
+ qedf_debug = QEDF_DEFAULT_LOG_MASK;
+ else
+ qedf_debug = val;
+
+ QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "Setting debug=0x%x.\n", val);
+ return count;
+}
+
+static ssize_t
+qedf_dbg_stop_io_on_error_cmd_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int cnt;
+ struct qedf_dbg_ctx *qedf_dbg =
+ (struct qedf_dbg_ctx *)filp->private_data;
+ struct qedf_ctx *qedf = container_of(qedf_dbg,
+ struct qedf_ctx, dbg_ctx);
+
+ QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n");
+ cnt = sprintf(buffer, "%s\n",
+ qedf->stop_io_on_error ? "true" : "false");
+
+ cnt = min_t(int, count, cnt - *ppos);
+ *ppos += cnt;
+ return cnt;
+}
+
+static ssize_t
+qedf_dbg_stop_io_on_error_cmd_write(struct file *filp,
+ const char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ void *kern_buf;
+ struct qedf_dbg_ctx *qedf_dbg =
+ (struct qedf_dbg_ctx *)filp->private_data;
+ struct qedf_ctx *qedf = container_of(qedf_dbg, struct qedf_ctx,
+ dbg_ctx);
+
+ QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n");
+
+ if (!count || *ppos)
+ return 0;
+
+ kern_buf = memdup_user(buffer, 6);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
+
+ if (strncmp(kern_buf, "false", 5) == 0)
+ qedf->stop_io_on_error = false;
+ else if (strncmp(kern_buf, "true", 4) == 0)
+ qedf->stop_io_on_error = true;
+ else if (strncmp(kern_buf, "now", 3) == 0)
+ /* Trigger from user to stop all I/O on this host */
+ set_bit(QEDF_DBG_STOP_IO, &qedf->flags);
+
+ kfree(kern_buf);
+ return count;
+}
+
+static int
+qedf_io_trace_show(struct seq_file *s, void *unused)
+{
+ int i, idx = 0;
+ struct qedf_ctx *qedf = s->private;
+ struct qedf_dbg_ctx *qedf_dbg = &qedf->dbg_ctx;
+ struct qedf_io_log *io_log;
+ unsigned long flags;
+
+ if (!qedf_io_tracing) {
+ seq_puts(s, "I/O tracing not enabled.\n");
+ goto out;
+ }
+
+ QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n");
+
+ spin_lock_irqsave(&qedf->io_trace_lock, flags);
+ idx = qedf->io_trace_idx;
+ for (i = 0; i < QEDF_IO_TRACE_SIZE; i++) {
+ io_log = &qedf->io_trace_buf[idx];
+ seq_printf(s, "%d:", io_log->direction);
+ seq_printf(s, "0x%x:", io_log->task_id);
+ seq_printf(s, "0x%06x:", io_log->port_id);
+ seq_printf(s, "%d:", io_log->lun);
+ seq_printf(s, "0x%02x:", io_log->op);
+ seq_printf(s, "0x%02x%02x%02x%02x:", io_log->lba[0],
+ io_log->lba[1], io_log->lba[2], io_log->lba[3]);
+ seq_printf(s, "%d:", io_log->bufflen);
+ seq_printf(s, "%d:", io_log->sg_count);
+ seq_printf(s, "0x%08x:", io_log->result);
+ seq_printf(s, "%lu:", io_log->jiffies);
+ seq_printf(s, "%d:", io_log->refcount);
+ seq_printf(s, "%d:", io_log->req_cpu);
+ seq_printf(s, "%d:", io_log->int_cpu);
+ seq_printf(s, "%d:", io_log->rsp_cpu);
+ seq_printf(s, "%d\n", io_log->sge_type);
+
+ idx++;
+ if (idx == QEDF_IO_TRACE_SIZE)
+ idx = 0;
+ }
+ spin_unlock_irqrestore(&qedf->io_trace_lock, flags);
+
+out:
+ return 0;
+}
+
+static int
+qedf_dbg_io_trace_open(struct inode *inode, struct file *file)
+{
+ struct qedf_dbg_ctx *qedf_dbg = inode->i_private;
+ struct qedf_ctx *qedf = container_of(qedf_dbg,
+ struct qedf_ctx, dbg_ctx);
+
+ return single_open(file, qedf_io_trace_show, qedf);
+}
+
+static int
+qedf_driver_stats_show(struct seq_file *s, void *unused)
+{
+ struct qedf_ctx *qedf = s->private;
+ struct qedf_rport *fcport;
+ struct fc_rport_priv *rdata;
+
+ seq_printf(s, "cmg_mgr free io_reqs: %d\n",
+ atomic_read(&qedf->cmd_mgr->free_list_cnt));
+ seq_printf(s, "slow SGEs: %d\n", qedf->slow_sge_ios);
+ seq_printf(s, "single SGEs: %d\n", qedf->single_sge_ios);
+ seq_printf(s, "fast SGEs: %d\n\n", qedf->fast_sge_ios);
+
+ seq_puts(s, "Offloaded ports:\n\n");
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(fcport, &qedf->fcports, peers) {
+ rdata = fcport->rdata;
+ if (rdata == NULL)
+ continue;
+ seq_printf(s, "%06x: free_sqes: %d, num_active_ios: %d\n",
+ rdata->ids.port_id, atomic_read(&fcport->free_sqes),
+ atomic_read(&fcport->num_active_ios));
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int
+qedf_dbg_driver_stats_open(struct inode *inode, struct file *file)
+{
+ struct qedf_dbg_ctx *qedf_dbg = inode->i_private;
+ struct qedf_ctx *qedf = container_of(qedf_dbg,
+ struct qedf_ctx, dbg_ctx);
+
+ return single_open(file, qedf_driver_stats_show, qedf);
+}
+
+static ssize_t
+qedf_dbg_clear_stats_cmd_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int cnt = 0;
+
+ /* Essentially a read stub */
+ cnt = min_t(int, count, cnt - *ppos);
+ *ppos += cnt;
+ return cnt;
+}
+
+static ssize_t
+qedf_dbg_clear_stats_cmd_write(struct file *filp,
+ const char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct qedf_dbg_ctx *qedf_dbg =
+ (struct qedf_dbg_ctx *)filp->private_data;
+ struct qedf_ctx *qedf = container_of(qedf_dbg, struct qedf_ctx,
+ dbg_ctx);
+
+ QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "Clearing stat counters.\n");
+
+ if (!count || *ppos)
+ return 0;
+
+ /* Clear stat counters exposed by 'stats' node */
+ qedf->slow_sge_ios = 0;
+ qedf->single_sge_ios = 0;
+ qedf->fast_sge_ios = 0;
+
+ return count;
+}
+
+static int
+qedf_offload_stats_show(struct seq_file *s, void *unused)
+{
+ struct qedf_ctx *qedf = s->private;
+ struct qed_fcoe_stats *fw_fcoe_stats;
+
+ fw_fcoe_stats = kmalloc(sizeof(struct qed_fcoe_stats), GFP_KERNEL);
+ if (!fw_fcoe_stats) {
+ QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate memory for "
+ "fw_fcoe_stats.\n");
+ goto out;
+ }
+
+ /* Query firmware for offload stats */
+ qed_ops->get_stats(qedf->cdev, fw_fcoe_stats);
+
+ seq_printf(s, "fcoe_rx_byte_cnt=%llu\n"
+ "fcoe_rx_data_pkt_cnt=%llu\n"
+ "fcoe_rx_xfer_pkt_cnt=%llu\n"
+ "fcoe_rx_other_pkt_cnt=%llu\n"
+ "fcoe_silent_drop_pkt_cmdq_full_cnt=%u\n"
+ "fcoe_silent_drop_pkt_crc_error_cnt=%u\n"
+ "fcoe_silent_drop_pkt_task_invalid_cnt=%u\n"
+ "fcoe_silent_drop_total_pkt_cnt=%u\n"
+ "fcoe_silent_drop_pkt_rq_full_cnt=%u\n"
+ "fcoe_tx_byte_cnt=%llu\n"
+ "fcoe_tx_data_pkt_cnt=%llu\n"
+ "fcoe_tx_xfer_pkt_cnt=%llu\n"
+ "fcoe_tx_other_pkt_cnt=%llu\n",
+ fw_fcoe_stats->fcoe_rx_byte_cnt,
+ fw_fcoe_stats->fcoe_rx_data_pkt_cnt,
+ fw_fcoe_stats->fcoe_rx_xfer_pkt_cnt,
+ fw_fcoe_stats->fcoe_rx_other_pkt_cnt,
+ fw_fcoe_stats->fcoe_silent_drop_pkt_cmdq_full_cnt,
+ fw_fcoe_stats->fcoe_silent_drop_pkt_crc_error_cnt,
+ fw_fcoe_stats->fcoe_silent_drop_pkt_task_invalid_cnt,
+ fw_fcoe_stats->fcoe_silent_drop_total_pkt_cnt,
+ fw_fcoe_stats->fcoe_silent_drop_pkt_rq_full_cnt,
+ fw_fcoe_stats->fcoe_tx_byte_cnt,
+ fw_fcoe_stats->fcoe_tx_data_pkt_cnt,
+ fw_fcoe_stats->fcoe_tx_xfer_pkt_cnt,
+ fw_fcoe_stats->fcoe_tx_other_pkt_cnt);
+
+ kfree(fw_fcoe_stats);
+out:
+ return 0;
+}
+
+static int
+qedf_dbg_offload_stats_open(struct inode *inode, struct file *file)
+{
+ struct qedf_dbg_ctx *qedf_dbg = inode->i_private;
+ struct qedf_ctx *qedf = container_of(qedf_dbg,
+ struct qedf_ctx, dbg_ctx);
+
+ return single_open(file, qedf_offload_stats_show, qedf);
+}
+
+
+const struct file_operations qedf_dbg_fops[] = {
+ qedf_dbg_fileops(qedf, fp_int),
+ qedf_dbg_fileops_seq(qedf, io_trace),
+ qedf_dbg_fileops(qedf, debug),
+ qedf_dbg_fileops(qedf, stop_io_on_error),
+ qedf_dbg_fileops_seq(qedf, driver_stats),
+ qedf_dbg_fileops(qedf, clear_stats),
+ qedf_dbg_fileops_seq(qedf, offload_stats),
+ /* This must be last */
+ { NULL, NULL },
+};
+
+#else /* CONFIG_DEBUG_FS */
+void qedf_dbg_host_init(struct qedf_dbg_ctx *);
+void qedf_dbg_host_exit(struct qedf_dbg_ctx *);
+void qedf_dbg_init(char *);
+void qedf_dbg_exit(void);
+#endif /* CONFIG_DEBUG_FS */