162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci// Copyright 2012 Cisco Systems, Inc.  All rights reserved.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/errno.h>
662306a36Sopenharmony_ci#include <linux/debugfs.h>
762306a36Sopenharmony_ci#include <linux/vmalloc.h>
862306a36Sopenharmony_ci#include "fnic.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic struct dentry *fnic_trace_debugfs_root;
1162306a36Sopenharmony_cistatic struct dentry *fnic_trace_debugfs_file;
1262306a36Sopenharmony_cistatic struct dentry *fnic_trace_enable;
1362306a36Sopenharmony_cistatic struct dentry *fnic_stats_debugfs_root;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic struct dentry *fnic_fc_trace_debugfs_file;
1662306a36Sopenharmony_cistatic struct dentry *fnic_fc_rdata_trace_debugfs_file;
1762306a36Sopenharmony_cistatic struct dentry *fnic_fc_trace_enable;
1862306a36Sopenharmony_cistatic struct dentry *fnic_fc_trace_clear;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct fc_trace_flag_type {
2162306a36Sopenharmony_ci	u8 fc_row_file;
2262306a36Sopenharmony_ci	u8 fc_normal_file;
2362306a36Sopenharmony_ci	u8 fnic_trace;
2462306a36Sopenharmony_ci	u8 fc_trace;
2562306a36Sopenharmony_ci	u8 fc_clear;
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic struct fc_trace_flag_type *fc_trc_flag;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * fnic_debugfs_init - Initialize debugfs for fnic debug logging
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Description:
3462306a36Sopenharmony_ci * When Debugfs is configured this routine sets up the fnic debugfs
3562306a36Sopenharmony_ci * file system. If not already created, this routine will create the
3662306a36Sopenharmony_ci * fnic directory and statistics directory for trace buffer and
3762306a36Sopenharmony_ci * stats logging.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ciint fnic_debugfs_init(void)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	fnic_stats_debugfs_root = debugfs_create_dir("statistics",
4462306a36Sopenharmony_ci						fnic_trace_debugfs_root);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* Allocate memory to structure */
4762306a36Sopenharmony_ci	fc_trc_flag = vmalloc(sizeof(struct fc_trace_flag_type));
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (fc_trc_flag) {
5062306a36Sopenharmony_ci		fc_trc_flag->fc_row_file = 0;
5162306a36Sopenharmony_ci		fc_trc_flag->fc_normal_file = 1;
5262306a36Sopenharmony_ci		fc_trc_flag->fnic_trace = 2;
5362306a36Sopenharmony_ci		fc_trc_flag->fc_trace = 3;
5462306a36Sopenharmony_ci		fc_trc_flag->fc_clear = 4;
5562306a36Sopenharmony_ci		return 0;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return -ENOMEM;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * fnic_debugfs_terminate - Tear down debugfs infrastructure
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * Description:
6562306a36Sopenharmony_ci * When Debugfs is configured this routine removes debugfs file system
6662306a36Sopenharmony_ci * elements that are specific to fnic.
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_civoid fnic_debugfs_terminate(void)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	debugfs_remove(fnic_stats_debugfs_root);
7162306a36Sopenharmony_ci	fnic_stats_debugfs_root = NULL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	debugfs_remove(fnic_trace_debugfs_root);
7462306a36Sopenharmony_ci	fnic_trace_debugfs_root = NULL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	vfree(fc_trc_flag);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * fnic_trace_ctrl_read -
8162306a36Sopenharmony_ci *          Read  trace_enable ,fc_trace_enable
8262306a36Sopenharmony_ci *              or fc_trace_clear debugfs file
8362306a36Sopenharmony_ci * @filp: The file pointer to read from.
8462306a36Sopenharmony_ci * @ubuf: The buffer to copy the data to.
8562306a36Sopenharmony_ci * @cnt: The number of bytes to read.
8662306a36Sopenharmony_ci * @ppos: The position in the file to start reading from.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Description:
8962306a36Sopenharmony_ci * This routine reads value of variable fnic_tracing_enabled or
9062306a36Sopenharmony_ci * fnic_fc_tracing_enabled or fnic_fc_trace_cleared
9162306a36Sopenharmony_ci * and stores into local @buf.
9262306a36Sopenharmony_ci * It will start reading file at @ppos and
9362306a36Sopenharmony_ci * copy up to @cnt of data to @ubuf from @buf.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Returns:
9662306a36Sopenharmony_ci * This function returns the amount of data that was read.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cistatic ssize_t fnic_trace_ctrl_read(struct file *filp,
9962306a36Sopenharmony_ci				  char __user *ubuf,
10062306a36Sopenharmony_ci				  size_t cnt, loff_t *ppos)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	char buf[64];
10362306a36Sopenharmony_ci	int len;
10462306a36Sopenharmony_ci	u8 *trace_type;
10562306a36Sopenharmony_ci	len = 0;
10662306a36Sopenharmony_ci	trace_type = (u8 *)filp->private_data;
10762306a36Sopenharmony_ci	if (*trace_type == fc_trc_flag->fnic_trace)
10862306a36Sopenharmony_ci		len = sprintf(buf, "%d\n", fnic_tracing_enabled);
10962306a36Sopenharmony_ci	else if (*trace_type == fc_trc_flag->fc_trace)
11062306a36Sopenharmony_ci		len = sprintf(buf, "%d\n", fnic_fc_tracing_enabled);
11162306a36Sopenharmony_ci	else if (*trace_type == fc_trc_flag->fc_clear)
11262306a36Sopenharmony_ci		len = sprintf(buf, "%d\n", fnic_fc_trace_cleared);
11362306a36Sopenharmony_ci	else
11462306a36Sopenharmony_ci		pr_err("fnic: Cannot read to any debugfs file\n");
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*
12062306a36Sopenharmony_ci * fnic_trace_ctrl_write -
12162306a36Sopenharmony_ci * Write to trace_enable, fc_trace_enable or
12262306a36Sopenharmony_ci *         fc_trace_clear debugfs file
12362306a36Sopenharmony_ci * @filp: The file pointer to write from.
12462306a36Sopenharmony_ci * @ubuf: The buffer to copy the data from.
12562306a36Sopenharmony_ci * @cnt: The number of bytes to write.
12662306a36Sopenharmony_ci * @ppos: The position in the file to start writing to.
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * Description:
12962306a36Sopenharmony_ci * This routine writes data from user buffer @ubuf to buffer @buf and
13062306a36Sopenharmony_ci * sets fc_trace_enable ,tracing_enable or fnic_fc_trace_cleared
13162306a36Sopenharmony_ci * value as per user input.
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * Returns:
13462306a36Sopenharmony_ci * This function returns the amount of data that was written.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic ssize_t fnic_trace_ctrl_write(struct file *filp,
13762306a36Sopenharmony_ci				  const char __user *ubuf,
13862306a36Sopenharmony_ci				  size_t cnt, loff_t *ppos)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	char buf[64];
14162306a36Sopenharmony_ci	unsigned long val;
14262306a36Sopenharmony_ci	int ret;
14362306a36Sopenharmony_ci	u8 *trace_type;
14462306a36Sopenharmony_ci	trace_type = (u8 *)filp->private_data;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (cnt >= sizeof(buf))
14762306a36Sopenharmony_ci		return -EINVAL;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (copy_from_user(&buf, ubuf, cnt))
15062306a36Sopenharmony_ci		return -EFAULT;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	buf[cnt] = 0;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	ret = kstrtoul(buf, 10, &val);
15562306a36Sopenharmony_ci	if (ret < 0)
15662306a36Sopenharmony_ci		return ret;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (*trace_type == fc_trc_flag->fnic_trace)
15962306a36Sopenharmony_ci		fnic_tracing_enabled = val;
16062306a36Sopenharmony_ci	else if (*trace_type == fc_trc_flag->fc_trace)
16162306a36Sopenharmony_ci		fnic_fc_tracing_enabled = val;
16262306a36Sopenharmony_ci	else if (*trace_type == fc_trc_flag->fc_clear)
16362306a36Sopenharmony_ci		fnic_fc_trace_cleared = val;
16462306a36Sopenharmony_ci	else
16562306a36Sopenharmony_ci		pr_err("fnic: cannot write to any debugfs file\n");
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	(*ppos)++;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return cnt;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic const struct file_operations fnic_trace_ctrl_fops = {
17362306a36Sopenharmony_ci	.owner = THIS_MODULE,
17462306a36Sopenharmony_ci	.open = simple_open,
17562306a36Sopenharmony_ci	.read = fnic_trace_ctrl_read,
17662306a36Sopenharmony_ci	.write = fnic_trace_ctrl_write,
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*
18062306a36Sopenharmony_ci * fnic_trace_debugfs_open - Open the fnic trace log
18162306a36Sopenharmony_ci * @inode: The inode pointer
18262306a36Sopenharmony_ci * @file: The file pointer to attach the log output
18362306a36Sopenharmony_ci *
18462306a36Sopenharmony_ci * Description:
18562306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation.
18662306a36Sopenharmony_ci * It allocates the necessary buffer for the log, fills the buffer from
18762306a36Sopenharmony_ci * the in-memory log and then returns a pointer to that log in
18862306a36Sopenharmony_ci * the private_data field in @file.
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * Returns:
19162306a36Sopenharmony_ci * This function returns zero if successful. On error it will return
19262306a36Sopenharmony_ci * a negative error value.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistatic int fnic_trace_debugfs_open(struct inode *inode,
19562306a36Sopenharmony_ci				  struct file *file)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	fnic_dbgfs_t *fnic_dbg_prt;
19862306a36Sopenharmony_ci	u8 *rdata_ptr;
19962306a36Sopenharmony_ci	rdata_ptr = (u8 *)inode->i_private;
20062306a36Sopenharmony_ci	fnic_dbg_prt = kzalloc(sizeof(fnic_dbgfs_t), GFP_KERNEL);
20162306a36Sopenharmony_ci	if (!fnic_dbg_prt)
20262306a36Sopenharmony_ci		return -ENOMEM;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (*rdata_ptr == fc_trc_flag->fnic_trace) {
20562306a36Sopenharmony_ci		fnic_dbg_prt->buffer = vzalloc(array3_size(3, trace_max_pages,
20662306a36Sopenharmony_ci							   PAGE_SIZE));
20762306a36Sopenharmony_ci		if (!fnic_dbg_prt->buffer) {
20862306a36Sopenharmony_ci			kfree(fnic_dbg_prt);
20962306a36Sopenharmony_ci			return -ENOMEM;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci		fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt);
21262306a36Sopenharmony_ci	} else {
21362306a36Sopenharmony_ci		fnic_dbg_prt->buffer =
21462306a36Sopenharmony_ci			vzalloc(array3_size(3, fnic_fc_trace_max_pages,
21562306a36Sopenharmony_ci					    PAGE_SIZE));
21662306a36Sopenharmony_ci		if (!fnic_dbg_prt->buffer) {
21762306a36Sopenharmony_ci			kfree(fnic_dbg_prt);
21862306a36Sopenharmony_ci			return -ENOMEM;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci		fnic_dbg_prt->buffer_len =
22162306a36Sopenharmony_ci			fnic_fc_trace_get_data(fnic_dbg_prt, *rdata_ptr);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci	file->private_data = fnic_dbg_prt;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci * fnic_trace_debugfs_lseek - Seek through a debugfs file
23062306a36Sopenharmony_ci * @file: The file pointer to seek through.
23162306a36Sopenharmony_ci * @offset: The offset to seek to or the amount to seek by.
23262306a36Sopenharmony_ci * @howto: Indicates how to seek.
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * Description:
23562306a36Sopenharmony_ci * This routine is the entry point for the debugfs lseek file operation.
23662306a36Sopenharmony_ci * The @howto parameter indicates whether @offset is the offset to directly
23762306a36Sopenharmony_ci * seek to, or if it is a value to seek forward or reverse by. This function
23862306a36Sopenharmony_ci * figures out what the new offset of the debugfs file will be and assigns
23962306a36Sopenharmony_ci * that value to the f_pos field of @file.
24062306a36Sopenharmony_ci *
24162306a36Sopenharmony_ci * Returns:
24262306a36Sopenharmony_ci * This function returns the new offset if successful and returns a negative
24362306a36Sopenharmony_ci * error if unable to process the seek.
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistatic loff_t fnic_trace_debugfs_lseek(struct file *file,
24662306a36Sopenharmony_ci					loff_t offset,
24762306a36Sopenharmony_ci					int howto)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
25062306a36Sopenharmony_ci	return fixed_size_llseek(file, offset, howto,
25162306a36Sopenharmony_ci				fnic_dbg_prt->buffer_len);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/*
25562306a36Sopenharmony_ci * fnic_trace_debugfs_read - Read a debugfs file
25662306a36Sopenharmony_ci * @file: The file pointer to read from.
25762306a36Sopenharmony_ci * @ubuf: The buffer to copy the data to.
25862306a36Sopenharmony_ci * @nbytes: The number of bytes to read.
25962306a36Sopenharmony_ci * @pos: The position in the file to start reading from.
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * Description:
26262306a36Sopenharmony_ci * This routine reads data from the buffer indicated in the private_data
26362306a36Sopenharmony_ci * field of @file. It will start reading at @pos and copy up to @nbytes of
26462306a36Sopenharmony_ci * data to @ubuf.
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * Returns:
26762306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be
26862306a36Sopenharmony_ci * less than @nbytes if the end of the file was reached).
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_cistatic ssize_t fnic_trace_debugfs_read(struct file *file,
27162306a36Sopenharmony_ci					char __user *ubuf,
27262306a36Sopenharmony_ci					size_t nbytes,
27362306a36Sopenharmony_ci					loff_t *pos)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
27662306a36Sopenharmony_ci	int rc = 0;
27762306a36Sopenharmony_ci	rc = simple_read_from_buffer(ubuf, nbytes, pos,
27862306a36Sopenharmony_ci				  fnic_dbg_prt->buffer,
27962306a36Sopenharmony_ci				  fnic_dbg_prt->buffer_len);
28062306a36Sopenharmony_ci	return rc;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/*
28462306a36Sopenharmony_ci * fnic_trace_debugfs_release - Release the buffer used to store
28562306a36Sopenharmony_ci * debugfs file data
28662306a36Sopenharmony_ci * @inode: The inode pointer
28762306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci * Description:
29062306a36Sopenharmony_ci * This routine frees the buffer that was allocated when the debugfs
29162306a36Sopenharmony_ci * file was opened.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * Returns:
29462306a36Sopenharmony_ci * This function returns zero.
29562306a36Sopenharmony_ci */
29662306a36Sopenharmony_cistatic int fnic_trace_debugfs_release(struct inode *inode,
29762306a36Sopenharmony_ci					  struct file *file)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	vfree(fnic_dbg_prt->buffer);
30262306a36Sopenharmony_ci	kfree(fnic_dbg_prt);
30362306a36Sopenharmony_ci	return 0;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic const struct file_operations fnic_trace_debugfs_fops = {
30762306a36Sopenharmony_ci	.owner = THIS_MODULE,
30862306a36Sopenharmony_ci	.open = fnic_trace_debugfs_open,
30962306a36Sopenharmony_ci	.llseek = fnic_trace_debugfs_lseek,
31062306a36Sopenharmony_ci	.read = fnic_trace_debugfs_read,
31162306a36Sopenharmony_ci	.release = fnic_trace_debugfs_release,
31262306a36Sopenharmony_ci};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * fnic_trace_debugfs_init - Initialize debugfs for fnic trace logging
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * Description:
31862306a36Sopenharmony_ci * When Debugfs is configured this routine sets up the fnic debugfs
31962306a36Sopenharmony_ci * file system. If not already created, this routine will create the
32062306a36Sopenharmony_ci * create file trace to log fnic trace buffer output into debugfs and
32162306a36Sopenharmony_ci * it will also create file trace_enable to control enable/disable of
32262306a36Sopenharmony_ci * trace logging into trace buffer.
32362306a36Sopenharmony_ci */
32462306a36Sopenharmony_civoid fnic_trace_debugfs_init(void)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	fnic_trace_enable = debugfs_create_file("tracing_enable",
32762306a36Sopenharmony_ci					S_IFREG|S_IRUGO|S_IWUSR,
32862306a36Sopenharmony_ci					fnic_trace_debugfs_root,
32962306a36Sopenharmony_ci					&(fc_trc_flag->fnic_trace),
33062306a36Sopenharmony_ci					&fnic_trace_ctrl_fops);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	fnic_trace_debugfs_file = debugfs_create_file("trace",
33362306a36Sopenharmony_ci					S_IFREG|S_IRUGO|S_IWUSR,
33462306a36Sopenharmony_ci					fnic_trace_debugfs_root,
33562306a36Sopenharmony_ci					&(fc_trc_flag->fnic_trace),
33662306a36Sopenharmony_ci					&fnic_trace_debugfs_fops);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci/*
34062306a36Sopenharmony_ci * fnic_trace_debugfs_terminate - Tear down debugfs infrastructure
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci * Description:
34362306a36Sopenharmony_ci * When Debugfs is configured this routine removes debugfs file system
34462306a36Sopenharmony_ci * elements that are specific to fnic trace logging.
34562306a36Sopenharmony_ci */
34662306a36Sopenharmony_civoid fnic_trace_debugfs_terminate(void)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	debugfs_remove(fnic_trace_debugfs_file);
34962306a36Sopenharmony_ci	fnic_trace_debugfs_file = NULL;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	debugfs_remove(fnic_trace_enable);
35262306a36Sopenharmony_ci	fnic_trace_enable = NULL;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci/*
35662306a36Sopenharmony_ci * fnic_fc_trace_debugfs_init -
35762306a36Sopenharmony_ci * Initialize debugfs for fnic control frame trace logging
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci * Description:
36062306a36Sopenharmony_ci * When Debugfs is configured this routine sets up the fnic_fc debugfs
36162306a36Sopenharmony_ci * file system. If not already created, this routine will create the
36262306a36Sopenharmony_ci * create file trace to log fnic fc trace buffer output into debugfs and
36362306a36Sopenharmony_ci * it will also create file fc_trace_enable to control enable/disable of
36462306a36Sopenharmony_ci * trace logging into trace buffer.
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_civoid fnic_fc_trace_debugfs_init(void)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	fnic_fc_trace_enable = debugfs_create_file("fc_trace_enable",
37062306a36Sopenharmony_ci					S_IFREG|S_IRUGO|S_IWUSR,
37162306a36Sopenharmony_ci					fnic_trace_debugfs_root,
37262306a36Sopenharmony_ci					&(fc_trc_flag->fc_trace),
37362306a36Sopenharmony_ci					&fnic_trace_ctrl_fops);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	fnic_fc_trace_clear = debugfs_create_file("fc_trace_clear",
37662306a36Sopenharmony_ci					S_IFREG|S_IRUGO|S_IWUSR,
37762306a36Sopenharmony_ci					fnic_trace_debugfs_root,
37862306a36Sopenharmony_ci					&(fc_trc_flag->fc_clear),
37962306a36Sopenharmony_ci					&fnic_trace_ctrl_fops);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	fnic_fc_rdata_trace_debugfs_file =
38262306a36Sopenharmony_ci		debugfs_create_file("fc_trace_rdata",
38362306a36Sopenharmony_ci				    S_IFREG|S_IRUGO|S_IWUSR,
38462306a36Sopenharmony_ci				    fnic_trace_debugfs_root,
38562306a36Sopenharmony_ci				    &(fc_trc_flag->fc_normal_file),
38662306a36Sopenharmony_ci				    &fnic_trace_debugfs_fops);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	fnic_fc_trace_debugfs_file =
38962306a36Sopenharmony_ci		debugfs_create_file("fc_trace",
39062306a36Sopenharmony_ci				    S_IFREG|S_IRUGO|S_IWUSR,
39162306a36Sopenharmony_ci				    fnic_trace_debugfs_root,
39262306a36Sopenharmony_ci				    &(fc_trc_flag->fc_row_file),
39362306a36Sopenharmony_ci				    &fnic_trace_debugfs_fops);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/*
39762306a36Sopenharmony_ci * fnic_fc_trace_debugfs_terminate - Tear down debugfs infrastructure
39862306a36Sopenharmony_ci *
39962306a36Sopenharmony_ci * Description:
40062306a36Sopenharmony_ci * When Debugfs is configured this routine removes debugfs file system
40162306a36Sopenharmony_ci * elements that are specific to fnic_fc trace logging.
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_civoid fnic_fc_trace_debugfs_terminate(void)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	debugfs_remove(fnic_fc_trace_debugfs_file);
40762306a36Sopenharmony_ci	fnic_fc_trace_debugfs_file = NULL;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	debugfs_remove(fnic_fc_rdata_trace_debugfs_file);
41062306a36Sopenharmony_ci	fnic_fc_rdata_trace_debugfs_file = NULL;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	debugfs_remove(fnic_fc_trace_enable);
41362306a36Sopenharmony_ci	fnic_fc_trace_enable = NULL;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	debugfs_remove(fnic_fc_trace_clear);
41662306a36Sopenharmony_ci	fnic_fc_trace_clear = NULL;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/*
42062306a36Sopenharmony_ci * fnic_reset_stats_open - Open the reset_stats file
42162306a36Sopenharmony_ci * @inode: The inode pointer.
42262306a36Sopenharmony_ci * @file: The file pointer to attach the stats reset flag.
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci * Description:
42562306a36Sopenharmony_ci * This routine opens a debugsfs file reset_stats and stores i_private data
42662306a36Sopenharmony_ci * to debug structure to retrieve later for while performing other
42762306a36Sopenharmony_ci * file oprations.
42862306a36Sopenharmony_ci *
42962306a36Sopenharmony_ci * Returns:
43062306a36Sopenharmony_ci * This function returns zero if successful.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic int fnic_reset_stats_open(struct inode *inode, struct file *file)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct stats_debug_info *debug;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL);
43762306a36Sopenharmony_ci	if (!debug)
43862306a36Sopenharmony_ci		return -ENOMEM;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	debug->i_private = inode->i_private;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	file->private_data = debug;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return 0;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/*
44862306a36Sopenharmony_ci * fnic_reset_stats_read - Read a reset_stats debugfs file
44962306a36Sopenharmony_ci * @filp: The file pointer to read from.
45062306a36Sopenharmony_ci * @ubuf: The buffer to copy the data to.
45162306a36Sopenharmony_ci * @cnt: The number of bytes to read.
45262306a36Sopenharmony_ci * @ppos: The position in the file to start reading from.
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci * Description:
45562306a36Sopenharmony_ci * This routine reads value of variable reset_stats
45662306a36Sopenharmony_ci * and stores into local @buf. It will start reading file at @ppos and
45762306a36Sopenharmony_ci * copy up to @cnt of data to @ubuf from @buf.
45862306a36Sopenharmony_ci *
45962306a36Sopenharmony_ci * Returns:
46062306a36Sopenharmony_ci * This function returns the amount of data that was read.
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_cistatic ssize_t fnic_reset_stats_read(struct file *file,
46362306a36Sopenharmony_ci					char __user *ubuf,
46462306a36Sopenharmony_ci					size_t cnt, loff_t *ppos)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	struct stats_debug_info *debug = file->private_data;
46762306a36Sopenharmony_ci	struct fnic *fnic = (struct fnic *)debug->i_private;
46862306a36Sopenharmony_ci	char buf[64];
46962306a36Sopenharmony_ci	int len;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	len = sprintf(buf, "%u\n", fnic->reset_stats);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/*
47762306a36Sopenharmony_ci * fnic_reset_stats_write - Write to reset_stats debugfs file
47862306a36Sopenharmony_ci * @filp: The file pointer to write from.
47962306a36Sopenharmony_ci * @ubuf: The buffer to copy the data from.
48062306a36Sopenharmony_ci * @cnt: The number of bytes to write.
48162306a36Sopenharmony_ci * @ppos: The position in the file to start writing to.
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * Description:
48462306a36Sopenharmony_ci * This routine writes data from user buffer @ubuf to buffer @buf and
48562306a36Sopenharmony_ci * resets cumulative stats of fnic.
48662306a36Sopenharmony_ci *
48762306a36Sopenharmony_ci * Returns:
48862306a36Sopenharmony_ci * This function returns the amount of data that was written.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic ssize_t fnic_reset_stats_write(struct file *file,
49162306a36Sopenharmony_ci					const char __user *ubuf,
49262306a36Sopenharmony_ci					size_t cnt, loff_t *ppos)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct stats_debug_info *debug = file->private_data;
49562306a36Sopenharmony_ci	struct fnic *fnic = (struct fnic *)debug->i_private;
49662306a36Sopenharmony_ci	struct fnic_stats *stats = &fnic->fnic_stats;
49762306a36Sopenharmony_ci	u64 *io_stats_p = (u64 *)&stats->io_stats;
49862306a36Sopenharmony_ci	u64 *fw_stats_p = (u64 *)&stats->fw_stats;
49962306a36Sopenharmony_ci	char buf[64];
50062306a36Sopenharmony_ci	unsigned long val;
50162306a36Sopenharmony_ci	int ret;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (cnt >= sizeof(buf))
50462306a36Sopenharmony_ci		return -EINVAL;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (copy_from_user(&buf, ubuf, cnt))
50762306a36Sopenharmony_ci		return -EFAULT;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	buf[cnt] = 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = kstrtoul(buf, 10, &val);
51262306a36Sopenharmony_ci	if (ret < 0)
51362306a36Sopenharmony_ci		return ret;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	fnic->reset_stats = val;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (fnic->reset_stats) {
51862306a36Sopenharmony_ci		/* Skip variable is used to avoid descrepancies to Num IOs
51962306a36Sopenharmony_ci		 * and IO Completions stats. Skip incrementing No IO Compls
52062306a36Sopenharmony_ci		 * for pending active IOs after reset stats
52162306a36Sopenharmony_ci		 */
52262306a36Sopenharmony_ci		atomic64_set(&fnic->io_cmpl_skip,
52362306a36Sopenharmony_ci			atomic64_read(&stats->io_stats.active_ios));
52462306a36Sopenharmony_ci		memset(&stats->abts_stats, 0, sizeof(struct abort_stats));
52562306a36Sopenharmony_ci		memset(&stats->term_stats, 0,
52662306a36Sopenharmony_ci			sizeof(struct terminate_stats));
52762306a36Sopenharmony_ci		memset(&stats->reset_stats, 0, sizeof(struct reset_stats));
52862306a36Sopenharmony_ci		memset(&stats->misc_stats, 0, sizeof(struct misc_stats));
52962306a36Sopenharmony_ci		memset(&stats->vlan_stats, 0, sizeof(struct vlan_stats));
53062306a36Sopenharmony_ci		memset(io_stats_p+1, 0,
53162306a36Sopenharmony_ci			sizeof(struct io_path_stats) - sizeof(u64));
53262306a36Sopenharmony_ci		memset(fw_stats_p+1, 0,
53362306a36Sopenharmony_ci			sizeof(struct fw_stats) - sizeof(u64));
53462306a36Sopenharmony_ci		ktime_get_real_ts64(&stats->stats_timestamps.last_reset_time);
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	(*ppos)++;
53862306a36Sopenharmony_ci	return cnt;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/*
54262306a36Sopenharmony_ci * fnic_reset_stats_release - Release the buffer used to store
54362306a36Sopenharmony_ci * debugfs file data
54462306a36Sopenharmony_ci * @inode: The inode pointer
54562306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release
54662306a36Sopenharmony_ci *
54762306a36Sopenharmony_ci * Description:
54862306a36Sopenharmony_ci * This routine frees the buffer that was allocated when the debugfs
54962306a36Sopenharmony_ci * file was opened.
55062306a36Sopenharmony_ci *
55162306a36Sopenharmony_ci * Returns:
55262306a36Sopenharmony_ci * This function returns zero.
55362306a36Sopenharmony_ci */
55462306a36Sopenharmony_cistatic int fnic_reset_stats_release(struct inode *inode,
55562306a36Sopenharmony_ci					struct file *file)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct stats_debug_info *debug = file->private_data;
55862306a36Sopenharmony_ci	kfree(debug);
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/*
56362306a36Sopenharmony_ci * fnic_stats_debugfs_open - Open the stats file for specific host
56462306a36Sopenharmony_ci * and get fnic stats.
56562306a36Sopenharmony_ci * @inode: The inode pointer.
56662306a36Sopenharmony_ci * @file: The file pointer to attach the specific host statistics.
56762306a36Sopenharmony_ci *
56862306a36Sopenharmony_ci * Description:
56962306a36Sopenharmony_ci * This routine opens a debugsfs file stats of specific host and print
57062306a36Sopenharmony_ci * fnic stats.
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * Returns:
57362306a36Sopenharmony_ci * This function returns zero if successful.
57462306a36Sopenharmony_ci */
57562306a36Sopenharmony_cistatic int fnic_stats_debugfs_open(struct inode *inode,
57662306a36Sopenharmony_ci					struct file *file)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct fnic *fnic = inode->i_private;
57962306a36Sopenharmony_ci	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
58062306a36Sopenharmony_ci	struct stats_debug_info *debug;
58162306a36Sopenharmony_ci	int buf_size = 2 * PAGE_SIZE;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL);
58462306a36Sopenharmony_ci	if (!debug)
58562306a36Sopenharmony_ci		return -ENOMEM;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	debug->debug_buffer = vmalloc(buf_size);
58862306a36Sopenharmony_ci	if (!debug->debug_buffer) {
58962306a36Sopenharmony_ci		kfree(debug);
59062306a36Sopenharmony_ci		return -ENOMEM;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	debug->buf_size = buf_size;
59462306a36Sopenharmony_ci	memset((void *)debug->debug_buffer, 0, buf_size);
59562306a36Sopenharmony_ci	debug->buffer_len = fnic_get_stats_data(debug, fnic_stats);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	file->private_data = debug;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci/*
60362306a36Sopenharmony_ci * fnic_stats_debugfs_read - Read a debugfs file
60462306a36Sopenharmony_ci * @file: The file pointer to read from.
60562306a36Sopenharmony_ci * @ubuf: The buffer to copy the data to.
60662306a36Sopenharmony_ci * @nbytes: The number of bytes to read.
60762306a36Sopenharmony_ci * @pos: The position in the file to start reading from.
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * Description:
61062306a36Sopenharmony_ci * This routine reads data from the buffer indicated in the private_data
61162306a36Sopenharmony_ci * field of @file. It will start reading at @pos and copy up to @nbytes of
61262306a36Sopenharmony_ci * data to @ubuf.
61362306a36Sopenharmony_ci *
61462306a36Sopenharmony_ci * Returns:
61562306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be
61662306a36Sopenharmony_ci * less than @nbytes if the end of the file was reached).
61762306a36Sopenharmony_ci */
61862306a36Sopenharmony_cistatic ssize_t fnic_stats_debugfs_read(struct file *file,
61962306a36Sopenharmony_ci					char __user *ubuf,
62062306a36Sopenharmony_ci					size_t nbytes,
62162306a36Sopenharmony_ci					loff_t *pos)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct stats_debug_info *debug = file->private_data;
62462306a36Sopenharmony_ci	int rc = 0;
62562306a36Sopenharmony_ci	rc = simple_read_from_buffer(ubuf, nbytes, pos,
62662306a36Sopenharmony_ci					debug->debug_buffer,
62762306a36Sopenharmony_ci					debug->buffer_len);
62862306a36Sopenharmony_ci	return rc;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/*
63262306a36Sopenharmony_ci * fnic_stats_stats_release - Release the buffer used to store
63362306a36Sopenharmony_ci * debugfs file data
63462306a36Sopenharmony_ci * @inode: The inode pointer
63562306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release
63662306a36Sopenharmony_ci *
63762306a36Sopenharmony_ci * Description:
63862306a36Sopenharmony_ci * This routine frees the buffer that was allocated when the debugfs
63962306a36Sopenharmony_ci * file was opened.
64062306a36Sopenharmony_ci *
64162306a36Sopenharmony_ci * Returns:
64262306a36Sopenharmony_ci * This function returns zero.
64362306a36Sopenharmony_ci */
64462306a36Sopenharmony_cistatic int fnic_stats_debugfs_release(struct inode *inode,
64562306a36Sopenharmony_ci					struct file *file)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct stats_debug_info *debug = file->private_data;
64862306a36Sopenharmony_ci	vfree(debug->debug_buffer);
64962306a36Sopenharmony_ci	kfree(debug);
65062306a36Sopenharmony_ci	return 0;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic const struct file_operations fnic_stats_debugfs_fops = {
65462306a36Sopenharmony_ci	.owner = THIS_MODULE,
65562306a36Sopenharmony_ci	.open = fnic_stats_debugfs_open,
65662306a36Sopenharmony_ci	.read = fnic_stats_debugfs_read,
65762306a36Sopenharmony_ci	.release = fnic_stats_debugfs_release,
65862306a36Sopenharmony_ci};
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic const struct file_operations fnic_reset_debugfs_fops = {
66162306a36Sopenharmony_ci	.owner = THIS_MODULE,
66262306a36Sopenharmony_ci	.open = fnic_reset_stats_open,
66362306a36Sopenharmony_ci	.read = fnic_reset_stats_read,
66462306a36Sopenharmony_ci	.write = fnic_reset_stats_write,
66562306a36Sopenharmony_ci	.release = fnic_reset_stats_release,
66662306a36Sopenharmony_ci};
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/*
66962306a36Sopenharmony_ci * fnic_stats_init - Initialize stats struct and create stats file per fnic
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * Description:
67262306a36Sopenharmony_ci * When Debugfs is configured this routine sets up the stats file per fnic
67362306a36Sopenharmony_ci * It will create file stats and reset_stats under statistics/host# directory
67462306a36Sopenharmony_ci * to log per fnic stats.
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_civoid fnic_stats_debugfs_init(struct fnic *fnic)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	char name[16];
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	snprintf(name, sizeof(name), "host%d", fnic->lport->host->host_no);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	fnic->fnic_stats_debugfs_host = debugfs_create_dir(name,
68362306a36Sopenharmony_ci						fnic_stats_debugfs_root);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	fnic->fnic_stats_debugfs_file = debugfs_create_file("stats",
68662306a36Sopenharmony_ci						S_IFREG|S_IRUGO|S_IWUSR,
68762306a36Sopenharmony_ci						fnic->fnic_stats_debugfs_host,
68862306a36Sopenharmony_ci						fnic,
68962306a36Sopenharmony_ci						&fnic_stats_debugfs_fops);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	fnic->fnic_reset_debugfs_file = debugfs_create_file("reset_stats",
69262306a36Sopenharmony_ci						S_IFREG|S_IRUGO|S_IWUSR,
69362306a36Sopenharmony_ci						fnic->fnic_stats_debugfs_host,
69462306a36Sopenharmony_ci						fnic,
69562306a36Sopenharmony_ci						&fnic_reset_debugfs_fops);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/*
69962306a36Sopenharmony_ci * fnic_stats_debugfs_remove - Tear down debugfs infrastructure of stats
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * Description:
70262306a36Sopenharmony_ci * When Debugfs is configured this routine removes debugfs file system
70362306a36Sopenharmony_ci * elements that are specific to fnic stats.
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_civoid fnic_stats_debugfs_remove(struct fnic *fnic)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	if (!fnic)
70862306a36Sopenharmony_ci		return;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	debugfs_remove(fnic->fnic_stats_debugfs_file);
71162306a36Sopenharmony_ci	fnic->fnic_stats_debugfs_file = NULL;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	debugfs_remove(fnic->fnic_reset_debugfs_file);
71462306a36Sopenharmony_ci	fnic->fnic_reset_debugfs_file = NULL;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	debugfs_remove(fnic->fnic_stats_debugfs_host);
71762306a36Sopenharmony_ci	fnic->fnic_stats_debugfs_host = NULL;
71862306a36Sopenharmony_ci}
719