]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: lpfc: Add debugfs support for cm framework buffers
authorJames Smart <jsmart2021@gmail.com>
Mon, 16 Aug 2021 16:28:57 +0000 (09:28 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 25 Aug 2021 02:56:34 +0000 (22:56 -0400)
Add support via debugfs to report the cm statistics, cm enablement, and rx
monitor information.

Link: https://lore.kernel.org/r/20210816162901.121235-13-jsmart2021@gmail.com
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.h

index 640075885540ce5888d3682b905ed48c1cc9b534..dd8cb111b1999b0163994ac6ff17205f25822527 100644 (file)
@@ -1357,6 +1357,8 @@ struct lpfc_hba {
 #ifdef LPFC_HDWQ_LOCK_STAT
        struct dentry *debug_lockstat;
 #endif
+       struct dentry *debug_cgn_buffer;
+       struct dentry *debug_rx_monitor;
        struct dentry *debug_ras_log;
        atomic_t nvmeio_trc_cnt;
        uint32_t nvmeio_trc_size;
index 6ff85ae57e79e10536fab9d72d81c1bb95c77dbe..bd6d459afce54f3c6170479ba58446b11d2c04b6 100644 (file)
@@ -5429,6 +5429,180 @@ lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
        return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
 }
 
+static int
+lpfc_cgn_buffer_open(struct inode *inode, struct file *file)
+{
+       struct lpfc_debug *debug;
+       int rc = -ENOMEM;
+
+       debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+       if (!debug)
+               goto out;
+
+       debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE);
+       if (!debug->buffer) {
+               kfree(debug);
+               goto out;
+       }
+
+       debug->i_private = inode->i_private;
+       file->private_data = debug;
+
+       rc = 0;
+out:
+       return rc;
+}
+
+static ssize_t
+lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes,
+                    loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *buffer = debug->buffer;
+       uint32_t *ptr;
+       int cnt, len = 0;
+
+       if (!phba->sli4_hba.pc_sli4_params.mi_ver || !phba->cgn_i) {
+               len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                                "Congestion Mgmt is not supported\n");
+               goto out;
+       }
+       ptr = (uint32_t *)phba->cgn_i->virt;
+       len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                        "Congestion Buffer Header\n");
+       /* Dump the first 32 bytes */
+       cnt = 32;
+       len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                        "000: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                        *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
+                        *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7));
+       ptr += 8;
+       len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                        "Congestion Buffer Data\n");
+       while (cnt < sizeof(struct lpfc_cgn_info)) {
+               if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) {
+                       len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                                        "Truncated . . .\n");
+                       break;
+               }
+               len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
+                                "%03x: %08x %08x %08x %08x "
+                                "%08x %08x %08x %08x\n",
+                                cnt, *ptr, *(ptr + 1), *(ptr + 2),
+                                *(ptr + 3), *(ptr + 4), *(ptr + 5),
+                                *(ptr + 6), *(ptr + 7));
+               cnt += 32;
+               ptr += 8;
+       }
+out:
+       return simple_read_from_buffer(buf, nbytes, ppos, buffer, len);
+}
+
+static int
+lpfc_cgn_buffer_release(struct inode *inode, struct file *file)
+{
+       struct lpfc_debug *debug = file->private_data;
+
+       vfree(debug->buffer);
+       kfree(debug);
+
+       return 0;
+}
+
+static int
+lpfc_rx_monitor_open(struct inode *inode, struct file *file)
+{
+       struct lpfc_rx_monitor_debug *debug;
+       int rc = -ENOMEM;
+
+       debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+       if (!debug)
+               goto out;
+
+       debug->buffer = vmalloc(MAX_DEBUGFS_RX_TABLE_SIZE);
+       if (!debug->buffer) {
+               kfree(debug);
+               goto out;
+       }
+
+       debug->i_private = inode->i_private;
+       file->private_data = debug;
+
+       rc = 0;
+out:
+       return rc;
+}
+
+static ssize_t
+lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes,
+                    loff_t *ppos)
+{
+       struct lpfc_rx_monitor_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *buffer = debug->buffer;
+       struct rxtable_entry *entry;
+       int i, len = 0, head, tail, last, start;
+
+       head = atomic_read(&phba->rxtable_idx_head);
+       while (head == LPFC_RXMONITOR_TABLE_IN_USE) {
+               /* Table is getting updated */
+               msleep(20);
+               head = atomic_read(&phba->rxtable_idx_head);
+       }
+
+       tail = atomic_xchg(&phba->rxtable_idx_tail, head);
+       if (!phba->rxtable || head == tail) {
+               len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len,
+                               "Rxtable is empty\n");
+               goto out;
+       }
+       last = (head > tail) ?  head : LPFC_MAX_RXMONITOR_ENTRY;
+       start = tail;
+
+       len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len,
+                       "        MaxBPI\t Total Data Cmd  Total Data Cmpl "
+                       "  Latency(us)    Avg IO Size\tMax IO Size   IO cnt "
+                       "Info BWutil(ms)\n");
+get_table:
+       for (i = start; i < last; i++) {
+               entry = &phba->rxtable[i];
+               len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len,
+                               "%3d:%12lld  %12lld\t%12lld\t"
+                               "%8lldus\t%8lld\t%10lld "
+                               "%8d   %2d %2d(%2d)\n",
+                               i, entry->max_bytes_per_interval,
+                               entry->total_bytes,
+                               entry->rcv_bytes,
+                               entry->avg_io_latency,
+                               entry->avg_io_size,
+                               entry->max_read_cnt,
+                               entry->io_cnt,
+                               entry->cmf_info,
+                               entry->timer_utilization,
+                               entry->timer_interval);
+       }
+
+       if (head != last) {
+               start = 0;
+               last = head;
+               goto get_table;
+       }
+out:
+       return simple_read_from_buffer(buf, nbytes, ppos, buffer, len);
+}
+
+static int
+lpfc_rx_monitor_release(struct inode *inode, struct file *file)
+{
+       struct lpfc_rx_monitor_debug *debug = file->private_data;
+
+       vfree(debug->buffer);
+       kfree(debug);
+
+       return 0;
+}
+
 #undef lpfc_debugfs_op_disc_trc
 static const struct file_operations lpfc_debugfs_op_disc_trc = {
        .owner =        THIS_MODULE,
@@ -5657,6 +5831,23 @@ static const struct file_operations lpfc_idiag_op_extAcc = {
        .write =        lpfc_idiag_extacc_write,
        .release =      lpfc_idiag_cmd_release,
 };
+#undef lpfc_cgn_buffer_op
+static const struct file_operations lpfc_cgn_buffer_op = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_cgn_buffer_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_cgn_buffer_read,
+       .release =      lpfc_cgn_buffer_release,
+};
+
+#undef lpfc_rx_monitor_op
+static const struct file_operations lpfc_rx_monitor_op = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_rx_monitor_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_rx_monitor_read,
+       .release =      lpfc_rx_monitor_release,
+};
 #endif
 
 /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
@@ -5907,6 +6098,32 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                        goto debug_failed;
                }
 
+               /* Congestion Info Buffer */
+               scnprintf(name, sizeof(name), "cgn_buffer");
+               phba->debug_cgn_buffer =
+                       debugfs_create_file(name, S_IFREG | 0644,
+                                           phba->hba_debugfs_root,
+                                           phba, &lpfc_cgn_buffer_op);
+               if (!phba->debug_cgn_buffer) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                        "6527 Cannot create debugfs "
+                                        "cgn_buffer\n");
+                       goto debug_failed;
+               }
+
+               /* RX Monitor */
+               scnprintf(name, sizeof(name), "rx_monitor");
+               phba->debug_rx_monitor =
+                       debugfs_create_file(name, S_IFREG | 0644,
+                                           phba->hba_debugfs_root,
+                                           phba, &lpfc_rx_monitor_op);
+               if (!phba->debug_rx_monitor) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                        "6528 Cannot create debugfs "
+                                        "rx_monitor\n");
+                       goto debug_failed;
+               }
+
                /* RAS log */
                snprintf(name, sizeof(name), "ras_log");
                phba->debug_ras_log =
@@ -6335,6 +6552,12 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
                phba->debug_hbqinfo = NULL;
 
+               debugfs_remove(phba->debug_cgn_buffer);
+               phba->debug_cgn_buffer = NULL;
+
+               debugfs_remove(phba->debug_rx_monitor);
+               phba->debug_rx_monitor = NULL;
+
                debugfs_remove(phba->debug_ras_log);
                phba->debug_ras_log = NULL;
 
index 7ab6d3b08698219662fd3c5504b7e01352c309e3..dd4cdd8563eb8186c0e31f00fa09197c32a2d230 100644 (file)
@@ -52,6 +52,9 @@
 /* scsistat output buffer size */
 #define LPFC_SCSISTAT_SIZE 8192
 
+/* Congestion Info Buffer size */
+#define LPFC_CGN_BUF_SIZE 8192
+
 #define LPFC_DEBUG_OUT_LINE_SZ 80
 
 /*
@@ -279,6 +282,12 @@ struct lpfc_idiag {
        void *ptr_private;
 };
 
+#define MAX_DEBUGFS_RX_TABLE_SIZE      (100 * LPFC_MAX_RXMONITOR_ENTRY)
+struct lpfc_rx_monitor_debug {
+       char *i_private;
+       char *buffer;
+};
+
 #else
 
 #define lpfc_nvmeio_data(phba, fmt, arg...) \