Commit 9f778708 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Add debugfs support for cm framework buffers

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: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7481811c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+223 −0
Original line number Diff line number Diff line
@@ -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;

+9 −0
Original line number Diff line number Diff line
@@ -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...) \