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