18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2012 Cisco Systems, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify
58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
158c2ecf20Sopenharmony_ci * SOFTWARE.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/mempool.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
228c2ecf20Sopenharmony_ci#include <linux/kallsyms.h>
238c2ecf20Sopenharmony_ci#include <linux/time.h>
248c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
258c2ecf20Sopenharmony_ci#include "fnic_io.h"
268c2ecf20Sopenharmony_ci#include "fnic.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciunsigned int trace_max_pages;
298c2ecf20Sopenharmony_cistatic int fnic_max_trace_entries;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic unsigned long fnic_trace_buf_p;
328c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(fnic_trace_lock);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic fnic_trace_dbg_t fnic_trace_entries;
358c2ecf20Sopenharmony_ciint fnic_tracing_enabled = 1;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* static char *fnic_fc_ctlr_trace_buf_p; */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int fc_trace_max_entries;
408c2ecf20Sopenharmony_cistatic unsigned long fnic_fc_ctlr_trace_buf_p;
418c2ecf20Sopenharmony_cistatic fnic_trace_dbg_t fc_trace_entries;
428c2ecf20Sopenharmony_ciint fnic_fc_tracing_enabled = 1;
438c2ecf20Sopenharmony_ciint fnic_fc_trace_cleared = 1;
448c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(fnic_fc_trace_lock);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * fnic_trace_get_buf - Give buffer pointer to user to fill up trace information
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * Description:
518c2ecf20Sopenharmony_ci * This routine gets next available trace buffer entry location @wr_idx
528c2ecf20Sopenharmony_ci * from allocated trace buffer pages and give that memory location
538c2ecf20Sopenharmony_ci * to user to store the trace information.
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci * Return Value:
568c2ecf20Sopenharmony_ci * This routine returns pointer to next available trace entry
578c2ecf20Sopenharmony_ci * @fnic_buf_head for user to fill trace information.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_cifnic_trace_data_t *fnic_trace_get_buf(void)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned long fnic_buf_head;
628c2ecf20Sopenharmony_ci	unsigned long flags;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	spin_lock_irqsave(&fnic_trace_lock, flags);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * Get next available memory location for writing trace information
688c2ecf20Sopenharmony_ci	 * at @wr_idx and increment @wr_idx
698c2ecf20Sopenharmony_ci	 */
708c2ecf20Sopenharmony_ci	fnic_buf_head =
718c2ecf20Sopenharmony_ci		fnic_trace_entries.page_offset[fnic_trace_entries.wr_idx];
728c2ecf20Sopenharmony_ci	fnic_trace_entries.wr_idx++;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * Verify if trace buffer is full then change wd_idx to
768c2ecf20Sopenharmony_ci	 * start from zero
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	if (fnic_trace_entries.wr_idx >= fnic_max_trace_entries)
798c2ecf20Sopenharmony_ci		fnic_trace_entries.wr_idx = 0;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/*
828c2ecf20Sopenharmony_ci	 * Verify if write index @wr_idx and read index @rd_idx are same then
838c2ecf20Sopenharmony_ci	 * increment @rd_idx to move to next entry in trace buffer
848c2ecf20Sopenharmony_ci	 */
858c2ecf20Sopenharmony_ci	if (fnic_trace_entries.wr_idx == fnic_trace_entries.rd_idx) {
868c2ecf20Sopenharmony_ci		fnic_trace_entries.rd_idx++;
878c2ecf20Sopenharmony_ci		if (fnic_trace_entries.rd_idx >= fnic_max_trace_entries)
888c2ecf20Sopenharmony_ci			fnic_trace_entries.rd_idx = 0;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&fnic_trace_lock, flags);
918c2ecf20Sopenharmony_ci	return (fnic_trace_data_t *)fnic_buf_head;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci * fnic_get_trace_data - Copy trace buffer to a memory file
968c2ecf20Sopenharmony_ci * @fnic_dbgfs_t: pointer to debugfs trace buffer
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * Description:
998c2ecf20Sopenharmony_ci * This routine gathers the fnic trace debugfs data from the fnic_trace_data_t
1008c2ecf20Sopenharmony_ci * buffer and dumps it to fnic_dbgfs_t. It will start at the rd_idx entry in
1018c2ecf20Sopenharmony_ci * the log and process the log until the end of the buffer. Then it will gather
1028c2ecf20Sopenharmony_ci * from the beginning of the log and process until the current entry @wr_idx.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * Return Value:
1058c2ecf20Sopenharmony_ci * This routine returns the amount of bytes that were dumped into fnic_dbgfs_t
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_ciint fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int rd_idx;
1108c2ecf20Sopenharmony_ci	int wr_idx;
1118c2ecf20Sopenharmony_ci	int len = 0;
1128c2ecf20Sopenharmony_ci	unsigned long flags;
1138c2ecf20Sopenharmony_ci	char str[KSYM_SYMBOL_LEN];
1148c2ecf20Sopenharmony_ci	struct timespec64 val;
1158c2ecf20Sopenharmony_ci	fnic_trace_data_t *tbp;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	spin_lock_irqsave(&fnic_trace_lock, flags);
1188c2ecf20Sopenharmony_ci	rd_idx = fnic_trace_entries.rd_idx;
1198c2ecf20Sopenharmony_ci	wr_idx = fnic_trace_entries.wr_idx;
1208c2ecf20Sopenharmony_ci	if (wr_idx < rd_idx) {
1218c2ecf20Sopenharmony_ci		while (1) {
1228c2ecf20Sopenharmony_ci			/* Start from read index @rd_idx */
1238c2ecf20Sopenharmony_ci			tbp = (fnic_trace_data_t *)
1248c2ecf20Sopenharmony_ci				  fnic_trace_entries.page_offset[rd_idx];
1258c2ecf20Sopenharmony_ci			if (!tbp) {
1268c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&fnic_trace_lock, flags);
1278c2ecf20Sopenharmony_ci				return 0;
1288c2ecf20Sopenharmony_ci			}
1298c2ecf20Sopenharmony_ci			/* Convert function pointer to function name */
1308c2ecf20Sopenharmony_ci			if (sizeof(unsigned long) < 8) {
1318c2ecf20Sopenharmony_ci				sprint_symbol(str, tbp->fnaddr.low);
1328c2ecf20Sopenharmony_ci				jiffies_to_timespec64(tbp->timestamp.low, &val);
1338c2ecf20Sopenharmony_ci			} else {
1348c2ecf20Sopenharmony_ci				sprint_symbol(str, tbp->fnaddr.val);
1358c2ecf20Sopenharmony_ci				jiffies_to_timespec64(tbp->timestamp.val, &val);
1368c2ecf20Sopenharmony_ci			}
1378c2ecf20Sopenharmony_ci			/*
1388c2ecf20Sopenharmony_ci			 * Dump trace buffer entry to memory file
1398c2ecf20Sopenharmony_ci			 * and increment read index @rd_idx
1408c2ecf20Sopenharmony_ci			 */
1418c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
1428c2ecf20Sopenharmony_ci				  (trace_max_pages * PAGE_SIZE * 3) - len,
1438c2ecf20Sopenharmony_ci				  "%16llu.%09lu %-50s %8x %8x %16llx %16llx "
1448c2ecf20Sopenharmony_ci				  "%16llx %16llx %16llx\n", (u64)val.tv_sec,
1458c2ecf20Sopenharmony_ci				  val.tv_nsec, str, tbp->host_no, tbp->tag,
1468c2ecf20Sopenharmony_ci				  tbp->data[0], tbp->data[1], tbp->data[2],
1478c2ecf20Sopenharmony_ci				  tbp->data[3], tbp->data[4]);
1488c2ecf20Sopenharmony_ci			rd_idx++;
1498c2ecf20Sopenharmony_ci			/*
1508c2ecf20Sopenharmony_ci			 * If rd_idx is reached to maximum trace entries
1518c2ecf20Sopenharmony_ci			 * then move rd_idx to zero
1528c2ecf20Sopenharmony_ci			 */
1538c2ecf20Sopenharmony_ci			if (rd_idx > (fnic_max_trace_entries-1))
1548c2ecf20Sopenharmony_ci				rd_idx = 0;
1558c2ecf20Sopenharmony_ci			/*
1568c2ecf20Sopenharmony_ci			 * Continure dumpping trace buffer entries into
1578c2ecf20Sopenharmony_ci			 * memory file till rd_idx reaches write index
1588c2ecf20Sopenharmony_ci			 */
1598c2ecf20Sopenharmony_ci			if (rd_idx == wr_idx)
1608c2ecf20Sopenharmony_ci				break;
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci	} else if (wr_idx > rd_idx) {
1638c2ecf20Sopenharmony_ci		while (1) {
1648c2ecf20Sopenharmony_ci			/* Start from read index @rd_idx */
1658c2ecf20Sopenharmony_ci			tbp = (fnic_trace_data_t *)
1668c2ecf20Sopenharmony_ci				  fnic_trace_entries.page_offset[rd_idx];
1678c2ecf20Sopenharmony_ci			if (!tbp) {
1688c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&fnic_trace_lock, flags);
1698c2ecf20Sopenharmony_ci				return 0;
1708c2ecf20Sopenharmony_ci			}
1718c2ecf20Sopenharmony_ci			/* Convert function pointer to function name */
1728c2ecf20Sopenharmony_ci			if (sizeof(unsigned long) < 8) {
1738c2ecf20Sopenharmony_ci				sprint_symbol(str, tbp->fnaddr.low);
1748c2ecf20Sopenharmony_ci				jiffies_to_timespec64(tbp->timestamp.low, &val);
1758c2ecf20Sopenharmony_ci			} else {
1768c2ecf20Sopenharmony_ci				sprint_symbol(str, tbp->fnaddr.val);
1778c2ecf20Sopenharmony_ci				jiffies_to_timespec64(tbp->timestamp.val, &val);
1788c2ecf20Sopenharmony_ci			}
1798c2ecf20Sopenharmony_ci			/*
1808c2ecf20Sopenharmony_ci			 * Dump trace buffer entry to memory file
1818c2ecf20Sopenharmony_ci			 * and increment read index @rd_idx
1828c2ecf20Sopenharmony_ci			 */
1838c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
1848c2ecf20Sopenharmony_ci				  (trace_max_pages * PAGE_SIZE * 3) - len,
1858c2ecf20Sopenharmony_ci				  "%16llu.%09lu %-50s %8x %8x %16llx %16llx "
1868c2ecf20Sopenharmony_ci				  "%16llx %16llx %16llx\n", (u64)val.tv_sec,
1878c2ecf20Sopenharmony_ci				  val.tv_nsec, str, tbp->host_no, tbp->tag,
1888c2ecf20Sopenharmony_ci				  tbp->data[0], tbp->data[1], tbp->data[2],
1898c2ecf20Sopenharmony_ci				  tbp->data[3], tbp->data[4]);
1908c2ecf20Sopenharmony_ci			rd_idx++;
1918c2ecf20Sopenharmony_ci			/*
1928c2ecf20Sopenharmony_ci			 * Continue dumpping trace buffer entries into
1938c2ecf20Sopenharmony_ci			 * memory file till rd_idx reaches write index
1948c2ecf20Sopenharmony_ci			 */
1958c2ecf20Sopenharmony_ci			if (rd_idx == wr_idx)
1968c2ecf20Sopenharmony_ci				break;
1978c2ecf20Sopenharmony_ci		}
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&fnic_trace_lock, flags);
2008c2ecf20Sopenharmony_ci	return len;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/*
2048c2ecf20Sopenharmony_ci * fnic_get_stats_data - Copy fnic stats buffer to a memory file
2058c2ecf20Sopenharmony_ci * @fnic_dbgfs_t: pointer to debugfs fnic stats buffer
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci * Description:
2088c2ecf20Sopenharmony_ci * This routine gathers the fnic stats debugfs data from the fnic_stats struct
2098c2ecf20Sopenharmony_ci * and dumps it to stats_debug_info.
2108c2ecf20Sopenharmony_ci *
2118c2ecf20Sopenharmony_ci * Return Value:
2128c2ecf20Sopenharmony_ci * This routine returns the amount of bytes that were dumped into
2138c2ecf20Sopenharmony_ci * stats_debug_info
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_ciint fnic_get_stats_data(struct stats_debug_info *debug,
2168c2ecf20Sopenharmony_ci			struct fnic_stats *stats)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int len = 0;
2198c2ecf20Sopenharmony_ci	int buf_size = debug->buf_size;
2208c2ecf20Sopenharmony_ci	struct timespec64 val1, val2;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ktime_get_real_ts64(&val1);
2238c2ecf20Sopenharmony_ci	len = scnprintf(debug->debug_buffer + len, buf_size - len,
2248c2ecf20Sopenharmony_ci		"------------------------------------------\n"
2258c2ecf20Sopenharmony_ci		 "\t\tTime\n"
2268c2ecf20Sopenharmony_ci		"------------------------------------------\n");
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2298c2ecf20Sopenharmony_ci		"Current time :          [%lld:%ld]\n"
2308c2ecf20Sopenharmony_ci		"Last stats reset time:  [%lld:%09ld]\n"
2318c2ecf20Sopenharmony_ci		"Last stats read time:   [%lld:%ld]\n"
2328c2ecf20Sopenharmony_ci		"delta since last reset: [%lld:%ld]\n"
2338c2ecf20Sopenharmony_ci		"delta since last read:  [%lld:%ld]\n",
2348c2ecf20Sopenharmony_ci	(s64)val1.tv_sec, val1.tv_nsec,
2358c2ecf20Sopenharmony_ci	(s64)stats->stats_timestamps.last_reset_time.tv_sec,
2368c2ecf20Sopenharmony_ci	stats->stats_timestamps.last_reset_time.tv_nsec,
2378c2ecf20Sopenharmony_ci	(s64)stats->stats_timestamps.last_read_time.tv_sec,
2388c2ecf20Sopenharmony_ci	stats->stats_timestamps.last_read_time.tv_nsec,
2398c2ecf20Sopenharmony_ci	(s64)timespec64_sub(val1, stats->stats_timestamps.last_reset_time).tv_sec,
2408c2ecf20Sopenharmony_ci	timespec64_sub(val1, stats->stats_timestamps.last_reset_time).tv_nsec,
2418c2ecf20Sopenharmony_ci	(s64)timespec64_sub(val1, stats->stats_timestamps.last_read_time).tv_sec,
2428c2ecf20Sopenharmony_ci	timespec64_sub(val1, stats->stats_timestamps.last_read_time).tv_nsec);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	stats->stats_timestamps.last_read_time = val1;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2478c2ecf20Sopenharmony_ci		  "------------------------------------------\n"
2488c2ecf20Sopenharmony_ci		  "\t\tIO Statistics\n"
2498c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
2508c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2518c2ecf20Sopenharmony_ci		  "Number of Active IOs: %lld\nMaximum Active IOs: %lld\n"
2528c2ecf20Sopenharmony_ci		  "Number of IOs: %lld\nNumber of IO Completions: %lld\n"
2538c2ecf20Sopenharmony_ci		  "Number of IO Failures: %lld\nNumber of IO NOT Found: %lld\n"
2548c2ecf20Sopenharmony_ci		  "Number of Memory alloc Failures: %lld\n"
2558c2ecf20Sopenharmony_ci		  "Number of IOREQ Null: %lld\n"
2568c2ecf20Sopenharmony_ci		  "Number of SCSI cmd pointer Null: %lld\n"
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		  "\nIO completion times: \n"
2598c2ecf20Sopenharmony_ci		  "            < 10 ms : %lld\n"
2608c2ecf20Sopenharmony_ci		  "     10 ms - 100 ms : %lld\n"
2618c2ecf20Sopenharmony_ci		  "    100 ms - 500 ms : %lld\n"
2628c2ecf20Sopenharmony_ci		  "    500 ms -   5 sec: %lld\n"
2638c2ecf20Sopenharmony_ci		  "     5 sec -  10 sec: %lld\n"
2648c2ecf20Sopenharmony_ci		  "    10 sec -  30 sec: %lld\n"
2658c2ecf20Sopenharmony_ci		  "            > 30 sec: %lld\n",
2668c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.active_ios),
2678c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.max_active_ios),
2688c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.num_ios),
2698c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_completions),
2708c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_failures),
2718c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_not_found),
2728c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.alloc_failures),
2738c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.ioreq_null),
2748c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.sc_null),
2758c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_0_to_10_msec),
2768c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_10_to_100_msec),
2778c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_100_to_500_msec),
2788c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_500_to_5000_msec),
2798c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_5000_to_10000_msec),
2808c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_btw_10000_to_30000_msec),
2818c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.io_greater_than_30000_msec));
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2848c2ecf20Sopenharmony_ci		  "\nCurrent Max IO time : %lld\n",
2858c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->io_stats.current_max_io_time));
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2888c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
2898c2ecf20Sopenharmony_ci		  "\t\tAbort Statistics\n"
2908c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
2938c2ecf20Sopenharmony_ci		  "Number of Aborts: %lld\n"
2948c2ecf20Sopenharmony_ci		  "Number of Abort Failures: %lld\n"
2958c2ecf20Sopenharmony_ci		  "Number of Abort Driver Timeouts: %lld\n"
2968c2ecf20Sopenharmony_ci		  "Number of Abort FW Timeouts: %lld\n"
2978c2ecf20Sopenharmony_ci		  "Number of Abort IO NOT Found: %lld\n"
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		  "Abort issued times: \n"
3008c2ecf20Sopenharmony_ci		  "            < 6 sec : %lld\n"
3018c2ecf20Sopenharmony_ci		  "     6 sec - 20 sec : %lld\n"
3028c2ecf20Sopenharmony_ci		  "    20 sec - 30 sec : %lld\n"
3038c2ecf20Sopenharmony_ci		  "    30 sec - 40 sec : %lld\n"
3048c2ecf20Sopenharmony_ci		  "    40 sec - 50 sec : %lld\n"
3058c2ecf20Sopenharmony_ci		  "    50 sec - 60 sec : %lld\n"
3068c2ecf20Sopenharmony_ci		  "            > 60 sec: %lld\n",
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.aborts),
3098c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_failures),
3108c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_drv_timeouts),
3118c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_fw_timeouts),
3128c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_io_not_found),
3138c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_0_to_6_sec),
3148c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_6_to_20_sec),
3158c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_20_to_30_sec),
3168c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_30_to_40_sec),
3178c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_40_to_50_sec),
3188c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_50_to_60_sec),
3198c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->abts_stats.abort_issued_greater_than_60_sec));
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3228c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
3238c2ecf20Sopenharmony_ci		  "\t\tTerminate Statistics\n"
3248c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3278c2ecf20Sopenharmony_ci		  "Number of Terminates: %lld\n"
3288c2ecf20Sopenharmony_ci		  "Maximum Terminates: %lld\n"
3298c2ecf20Sopenharmony_ci		  "Number of Terminate Driver Timeouts: %lld\n"
3308c2ecf20Sopenharmony_ci		  "Number of Terminate FW Timeouts: %lld\n"
3318c2ecf20Sopenharmony_ci		  "Number of Terminate IO NOT Found: %lld\n"
3328c2ecf20Sopenharmony_ci		  "Number of Terminate Failures: %lld\n",
3338c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.terminates),
3348c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.max_terminates),
3358c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.terminate_drv_timeouts),
3368c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.terminate_fw_timeouts),
3378c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.terminate_io_not_found),
3388c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->term_stats.terminate_failures));
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3418c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
3428c2ecf20Sopenharmony_ci		  "\t\tReset Statistics\n"
3438c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3468c2ecf20Sopenharmony_ci		  "Number of Device Resets: %lld\n"
3478c2ecf20Sopenharmony_ci		  "Number of Device Reset Failures: %lld\n"
3488c2ecf20Sopenharmony_ci		  "Number of Device Reset Aborts: %lld\n"
3498c2ecf20Sopenharmony_ci		  "Number of Device Reset Timeouts: %lld\n"
3508c2ecf20Sopenharmony_ci		  "Number of Device Reset Terminates: %lld\n"
3518c2ecf20Sopenharmony_ci		  "Number of FW Resets: %lld\n"
3528c2ecf20Sopenharmony_ci		  "Number of FW Reset Completions: %lld\n"
3538c2ecf20Sopenharmony_ci		  "Number of FW Reset Failures: %lld\n"
3548c2ecf20Sopenharmony_ci		  "Number of Fnic Reset: %lld\n"
3558c2ecf20Sopenharmony_ci		  "Number of Fnic Reset Completions: %lld\n"
3568c2ecf20Sopenharmony_ci		  "Number of Fnic Reset Failures: %lld\n",
3578c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.device_resets),
3588c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.device_reset_failures),
3598c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.device_reset_aborts),
3608c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.device_reset_timeouts),
3618c2ecf20Sopenharmony_ci		  (u64)atomic64_read(
3628c2ecf20Sopenharmony_ci			  &stats->reset_stats.device_reset_terminates),
3638c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.fw_resets),
3648c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.fw_reset_completions),
3658c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.fw_reset_failures),
3668c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.fnic_resets),
3678c2ecf20Sopenharmony_ci		  (u64)atomic64_read(
3688c2ecf20Sopenharmony_ci			  &stats->reset_stats.fnic_reset_completions),
3698c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->reset_stats.fnic_reset_failures));
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3728c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
3738c2ecf20Sopenharmony_ci		  "\t\tFirmware Statistics\n"
3748c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3778c2ecf20Sopenharmony_ci		  "Number of Active FW Requests %lld\n"
3788c2ecf20Sopenharmony_ci		  "Maximum FW Requests: %lld\n"
3798c2ecf20Sopenharmony_ci		  "Number of FW out of resources: %lld\n"
3808c2ecf20Sopenharmony_ci		  "Number of FW IO errors: %lld\n",
3818c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->fw_stats.active_fw_reqs),
3828c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->fw_stats.max_fw_reqs),
3838c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->fw_stats.fw_out_of_resources),
3848c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->fw_stats.io_fw_errs));
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3878c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
3888c2ecf20Sopenharmony_ci		  "\t\tVlan Discovery Statistics\n"
3898c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
3928c2ecf20Sopenharmony_ci		  "Number of Vlan Discovery Requests Sent %lld\n"
3938c2ecf20Sopenharmony_ci		  "Vlan Response Received with no FCF VLAN ID: %lld\n"
3948c2ecf20Sopenharmony_ci		  "No solicitations recvd after vlan set, expiry count: %lld\n"
3958c2ecf20Sopenharmony_ci		  "Flogi rejects count: %lld\n",
3968c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->vlan_stats.vlan_disc_reqs),
3978c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->vlan_stats.resp_withno_vlanID),
3988c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->vlan_stats.sol_expiry_count),
3998c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->vlan_stats.flogi_rejects));
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
4028c2ecf20Sopenharmony_ci		  "\n------------------------------------------\n"
4038c2ecf20Sopenharmony_ci		  "\t\tOther Important Statistics\n"
4048c2ecf20Sopenharmony_ci		  "------------------------------------------\n");
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	jiffies_to_timespec64(stats->misc_stats.last_isr_time, &val1);
4078c2ecf20Sopenharmony_ci	jiffies_to_timespec64(stats->misc_stats.last_ack_time, &val2);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
4108c2ecf20Sopenharmony_ci		  "Last ISR time: %llu (%8llu.%09lu)\n"
4118c2ecf20Sopenharmony_ci		  "Last ACK time: %llu (%8llu.%09lu)\n"
4128c2ecf20Sopenharmony_ci		  "Max ISR jiffies: %llu\n"
4138c2ecf20Sopenharmony_ci		  "Max ISR time (ms) (0 denotes < 1 ms): %llu\n"
4148c2ecf20Sopenharmony_ci		  "Corr. work done: %llu\n"
4158c2ecf20Sopenharmony_ci		  "Number of ISRs: %lld\n"
4168c2ecf20Sopenharmony_ci		  "Maximum CQ Entries: %lld\n"
4178c2ecf20Sopenharmony_ci		  "Number of ACK index out of range: %lld\n"
4188c2ecf20Sopenharmony_ci		  "Number of data count mismatch: %lld\n"
4198c2ecf20Sopenharmony_ci		  "Number of FCPIO Timeouts: %lld\n"
4208c2ecf20Sopenharmony_ci		  "Number of FCPIO Aborted: %lld\n"
4218c2ecf20Sopenharmony_ci		  "Number of SGL Invalid: %lld\n"
4228c2ecf20Sopenharmony_ci		  "Number of Copy WQ Alloc Failures for ABTs: %lld\n"
4238c2ecf20Sopenharmony_ci		  "Number of Copy WQ Alloc Failures for Device Reset: %lld\n"
4248c2ecf20Sopenharmony_ci		  "Number of Copy WQ Alloc Failures for IOs: %lld\n"
4258c2ecf20Sopenharmony_ci		  "Number of no icmnd itmf Completions: %lld\n"
4268c2ecf20Sopenharmony_ci		  "Number of Check Conditions encountered: %lld\n"
4278c2ecf20Sopenharmony_ci		  "Number of QUEUE Fulls: %lld\n"
4288c2ecf20Sopenharmony_ci		  "Number of rport not ready: %lld\n"
4298c2ecf20Sopenharmony_ci		  "Number of receive frame errors: %lld\n",
4308c2ecf20Sopenharmony_ci		  (u64)stats->misc_stats.last_isr_time,
4318c2ecf20Sopenharmony_ci		  (s64)val1.tv_sec, val1.tv_nsec,
4328c2ecf20Sopenharmony_ci		  (u64)stats->misc_stats.last_ack_time,
4338c2ecf20Sopenharmony_ci		  (s64)val2.tv_sec, val2.tv_nsec,
4348c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.max_isr_jiffies),
4358c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.max_isr_time_ms),
4368c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.corr_work_done),
4378c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.isr_count),
4388c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.max_cq_entries),
4398c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.ack_index_out_of_range),
4408c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.data_count_mismatch),
4418c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.fcpio_timeout),
4428c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.fcpio_aborted),
4438c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.sgl_invalid),
4448c2ecf20Sopenharmony_ci		  (u64)atomic64_read(
4458c2ecf20Sopenharmony_ci			  &stats->misc_stats.abts_cpwq_alloc_failures),
4468c2ecf20Sopenharmony_ci		  (u64)atomic64_read(
4478c2ecf20Sopenharmony_ci			  &stats->misc_stats.devrst_cpwq_alloc_failures),
4488c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.io_cpwq_alloc_failures),
4498c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.no_icmnd_itmf_cmpls),
4508c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.check_condition),
4518c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.queue_fulls),
4528c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.rport_not_ready),
4538c2ecf20Sopenharmony_ci		  (u64)atomic64_read(&stats->misc_stats.frame_errors));
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	len += scnprintf(debug->debug_buffer + len, buf_size - len,
4568c2ecf20Sopenharmony_ci			"Firmware reported port speed: %llu\n",
4578c2ecf20Sopenharmony_ci			(u64)atomic64_read(
4588c2ecf20Sopenharmony_ci				&stats->misc_stats.current_port_speed));
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return len;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci/*
4658c2ecf20Sopenharmony_ci * fnic_trace_buf_init - Initialize fnic trace buffer logging facility
4668c2ecf20Sopenharmony_ci *
4678c2ecf20Sopenharmony_ci * Description:
4688c2ecf20Sopenharmony_ci * Initialize trace buffer data structure by allocating required memory and
4698c2ecf20Sopenharmony_ci * setting page_offset information for every trace entry by adding trace entry
4708c2ecf20Sopenharmony_ci * length to previous page_offset value.
4718c2ecf20Sopenharmony_ci */
4728c2ecf20Sopenharmony_ciint fnic_trace_buf_init(void)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	unsigned long fnic_buf_head;
4758c2ecf20Sopenharmony_ci	int i;
4768c2ecf20Sopenharmony_ci	int err = 0;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	trace_max_pages = fnic_trace_max_pages;
4798c2ecf20Sopenharmony_ci	fnic_max_trace_entries = (trace_max_pages * PAGE_SIZE)/
4808c2ecf20Sopenharmony_ci					  FNIC_ENTRY_SIZE_BYTES;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	fnic_trace_buf_p = (unsigned long)vzalloc(trace_max_pages * PAGE_SIZE);
4838c2ecf20Sopenharmony_ci	if (!fnic_trace_buf_p) {
4848c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "Failed to allocate memory "
4858c2ecf20Sopenharmony_ci				  "for fnic_trace_buf_p\n");
4868c2ecf20Sopenharmony_ci		err = -ENOMEM;
4878c2ecf20Sopenharmony_ci		goto err_fnic_trace_buf_init;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	fnic_trace_entries.page_offset =
4918c2ecf20Sopenharmony_ci		vmalloc(array_size(fnic_max_trace_entries,
4928c2ecf20Sopenharmony_ci				   sizeof(unsigned long)));
4938c2ecf20Sopenharmony_ci	if (!fnic_trace_entries.page_offset) {
4948c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "Failed to allocate memory for"
4958c2ecf20Sopenharmony_ci				  " page_offset\n");
4968c2ecf20Sopenharmony_ci		if (fnic_trace_buf_p) {
4978c2ecf20Sopenharmony_ci			vfree((void *)fnic_trace_buf_p);
4988c2ecf20Sopenharmony_ci			fnic_trace_buf_p = 0;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci		err = -ENOMEM;
5018c2ecf20Sopenharmony_ci		goto err_fnic_trace_buf_init;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci	memset((void *)fnic_trace_entries.page_offset, 0,
5048c2ecf20Sopenharmony_ci		  (fnic_max_trace_entries * sizeof(unsigned long)));
5058c2ecf20Sopenharmony_ci	fnic_trace_entries.wr_idx = fnic_trace_entries.rd_idx = 0;
5068c2ecf20Sopenharmony_ci	fnic_buf_head = fnic_trace_buf_p;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/*
5098c2ecf20Sopenharmony_ci	 * Set page_offset field of fnic_trace_entries struct by
5108c2ecf20Sopenharmony_ci	 * calculating memory location for every trace entry using
5118c2ecf20Sopenharmony_ci	 * length of each trace entry
5128c2ecf20Sopenharmony_ci	 */
5138c2ecf20Sopenharmony_ci	for (i = 0; i < fnic_max_trace_entries; i++) {
5148c2ecf20Sopenharmony_ci		fnic_trace_entries.page_offset[i] = fnic_buf_head;
5158c2ecf20Sopenharmony_ci		fnic_buf_head += FNIC_ENTRY_SIZE_BYTES;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	fnic_trace_debugfs_init();
5188c2ecf20Sopenharmony_ci	pr_info("fnic: Successfully Initialized Trace Buffer\n");
5198c2ecf20Sopenharmony_ci	return err;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cierr_fnic_trace_buf_init:
5228c2ecf20Sopenharmony_ci	return err;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci/*
5268c2ecf20Sopenharmony_ci * fnic_trace_free - Free memory of fnic trace data structures.
5278c2ecf20Sopenharmony_ci */
5288c2ecf20Sopenharmony_civoid fnic_trace_free(void)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	fnic_tracing_enabled = 0;
5318c2ecf20Sopenharmony_ci	fnic_trace_debugfs_terminate();
5328c2ecf20Sopenharmony_ci	if (fnic_trace_entries.page_offset) {
5338c2ecf20Sopenharmony_ci		vfree((void *)fnic_trace_entries.page_offset);
5348c2ecf20Sopenharmony_ci		fnic_trace_entries.page_offset = NULL;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci	if (fnic_trace_buf_p) {
5378c2ecf20Sopenharmony_ci		vfree((void *)fnic_trace_buf_p);
5388c2ecf20Sopenharmony_ci		fnic_trace_buf_p = 0;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci	printk(KERN_INFO PFX "Successfully Freed Trace Buffer\n");
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/*
5448c2ecf20Sopenharmony_ci * fnic_fc_ctlr_trace_buf_init -
5458c2ecf20Sopenharmony_ci * Initialize trace buffer to log fnic control frames
5468c2ecf20Sopenharmony_ci * Description:
5478c2ecf20Sopenharmony_ci * Initialize trace buffer data structure by allocating
5488c2ecf20Sopenharmony_ci * required memory for trace data as well as for Indexes.
5498c2ecf20Sopenharmony_ci * Frame size is 256 bytes and
5508c2ecf20Sopenharmony_ci * memory is allocated for 1024 entries of 256 bytes.
5518c2ecf20Sopenharmony_ci * Page_offset(Index) is set to the address of trace entry
5528c2ecf20Sopenharmony_ci * and page_offset is initialized by adding frame size
5538c2ecf20Sopenharmony_ci * to the previous page_offset entry.
5548c2ecf20Sopenharmony_ci */
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ciint fnic_fc_trace_init(void)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	unsigned long fc_trace_buf_head;
5598c2ecf20Sopenharmony_ci	int err = 0;
5608c2ecf20Sopenharmony_ci	int i;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	fc_trace_max_entries = (fnic_fc_trace_max_pages * PAGE_SIZE)/
5638c2ecf20Sopenharmony_ci				FC_TRC_SIZE_BYTES;
5648c2ecf20Sopenharmony_ci	fnic_fc_ctlr_trace_buf_p =
5658c2ecf20Sopenharmony_ci		(unsigned long)vmalloc(array_size(PAGE_SIZE,
5668c2ecf20Sopenharmony_ci						  fnic_fc_trace_max_pages));
5678c2ecf20Sopenharmony_ci	if (!fnic_fc_ctlr_trace_buf_p) {
5688c2ecf20Sopenharmony_ci		pr_err("fnic: Failed to allocate memory for "
5698c2ecf20Sopenharmony_ci		       "FC Control Trace Buf\n");
5708c2ecf20Sopenharmony_ci		err = -ENOMEM;
5718c2ecf20Sopenharmony_ci		goto err_fnic_fc_ctlr_trace_buf_init;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	memset((void *)fnic_fc_ctlr_trace_buf_p, 0,
5758c2ecf20Sopenharmony_ci			fnic_fc_trace_max_pages * PAGE_SIZE);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* Allocate memory for page offset */
5788c2ecf20Sopenharmony_ci	fc_trace_entries.page_offset =
5798c2ecf20Sopenharmony_ci		vmalloc(array_size(fc_trace_max_entries,
5808c2ecf20Sopenharmony_ci				   sizeof(unsigned long)));
5818c2ecf20Sopenharmony_ci	if (!fc_trace_entries.page_offset) {
5828c2ecf20Sopenharmony_ci		pr_err("fnic:Failed to allocate memory for page_offset\n");
5838c2ecf20Sopenharmony_ci		if (fnic_fc_ctlr_trace_buf_p) {
5848c2ecf20Sopenharmony_ci			pr_err("fnic: Freeing FC Control Trace Buf\n");
5858c2ecf20Sopenharmony_ci			vfree((void *)fnic_fc_ctlr_trace_buf_p);
5868c2ecf20Sopenharmony_ci			fnic_fc_ctlr_trace_buf_p = 0;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci		err = -ENOMEM;
5898c2ecf20Sopenharmony_ci		goto err_fnic_fc_ctlr_trace_buf_init;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	memset((void *)fc_trace_entries.page_offset, 0,
5928c2ecf20Sopenharmony_ci	       (fc_trace_max_entries * sizeof(unsigned long)));
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	fc_trace_entries.rd_idx = fc_trace_entries.wr_idx = 0;
5958c2ecf20Sopenharmony_ci	fc_trace_buf_head = fnic_fc_ctlr_trace_buf_p;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/*
5988c2ecf20Sopenharmony_ci	* Set up fc_trace_entries.page_offset field with memory location
5998c2ecf20Sopenharmony_ci	* for every trace entry
6008c2ecf20Sopenharmony_ci	*/
6018c2ecf20Sopenharmony_ci	for (i = 0; i < fc_trace_max_entries; i++) {
6028c2ecf20Sopenharmony_ci		fc_trace_entries.page_offset[i] = fc_trace_buf_head;
6038c2ecf20Sopenharmony_ci		fc_trace_buf_head += FC_TRC_SIZE_BYTES;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci	fnic_fc_trace_debugfs_init();
6068c2ecf20Sopenharmony_ci	pr_info("fnic: Successfully Initialized FC_CTLR Trace Buffer\n");
6078c2ecf20Sopenharmony_ci	return err;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cierr_fnic_fc_ctlr_trace_buf_init:
6108c2ecf20Sopenharmony_ci	return err;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/*
6148c2ecf20Sopenharmony_ci * Fnic_fc_ctlr_trace_free - Free memory of fnic_fc_ctlr trace data structures.
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_civoid fnic_fc_trace_free(void)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	fnic_fc_tracing_enabled = 0;
6198c2ecf20Sopenharmony_ci	fnic_fc_trace_debugfs_terminate();
6208c2ecf20Sopenharmony_ci	if (fc_trace_entries.page_offset) {
6218c2ecf20Sopenharmony_ci		vfree((void *)fc_trace_entries.page_offset);
6228c2ecf20Sopenharmony_ci		fc_trace_entries.page_offset = NULL;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci	if (fnic_fc_ctlr_trace_buf_p) {
6258c2ecf20Sopenharmony_ci		vfree((void *)fnic_fc_ctlr_trace_buf_p);
6268c2ecf20Sopenharmony_ci		fnic_fc_ctlr_trace_buf_p = 0;
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci	pr_info("fnic:Successfully FC_CTLR Freed Trace Buffer\n");
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci/*
6328c2ecf20Sopenharmony_ci * fnic_fc_ctlr_set_trace_data:
6338c2ecf20Sopenharmony_ci *       Maintain rd & wr idx accordingly and set data
6348c2ecf20Sopenharmony_ci * Passed parameters:
6358c2ecf20Sopenharmony_ci *       host_no: host number accociated with fnic
6368c2ecf20Sopenharmony_ci *       frame_type: send_frame, rece_frame or link event
6378c2ecf20Sopenharmony_ci *       fc_frame: pointer to fc_frame
6388c2ecf20Sopenharmony_ci *       frame_len: Length of the fc_frame
6398c2ecf20Sopenharmony_ci * Description:
6408c2ecf20Sopenharmony_ci *   This routine will get next available wr_idx and
6418c2ecf20Sopenharmony_ci *   copy all passed trace data to the buffer pointed by wr_idx
6428c2ecf20Sopenharmony_ci *   and increment wr_idx. It will also make sure that we dont
6438c2ecf20Sopenharmony_ci *   overwrite the entry which we are reading and also
6448c2ecf20Sopenharmony_ci *   wrap around if we reach the maximum entries.
6458c2ecf20Sopenharmony_ci * Returned Value:
6468c2ecf20Sopenharmony_ci *   It will return 0 for success or -1 for failure
6478c2ecf20Sopenharmony_ci */
6488c2ecf20Sopenharmony_ciint fnic_fc_trace_set_data(u32 host_no, u8 frame_type,
6498c2ecf20Sopenharmony_ci				char *frame, u32 fc_trc_frame_len)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	unsigned long flags;
6528c2ecf20Sopenharmony_ci	struct fc_trace_hdr *fc_buf;
6538c2ecf20Sopenharmony_ci	unsigned long eth_fcoe_hdr_len;
6548c2ecf20Sopenharmony_ci	char *fc_trace;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (fnic_fc_tracing_enabled == 0)
6578c2ecf20Sopenharmony_ci		return 0;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	spin_lock_irqsave(&fnic_fc_trace_lock, flags);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (fnic_fc_trace_cleared == 1) {
6628c2ecf20Sopenharmony_ci		fc_trace_entries.rd_idx = fc_trace_entries.wr_idx = 0;
6638c2ecf20Sopenharmony_ci		pr_info("fnic: Resetting the read idx\n");
6648c2ecf20Sopenharmony_ci		memset((void *)fnic_fc_ctlr_trace_buf_p, 0,
6658c2ecf20Sopenharmony_ci				fnic_fc_trace_max_pages * PAGE_SIZE);
6668c2ecf20Sopenharmony_ci		fnic_fc_trace_cleared = 0;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	fc_buf = (struct fc_trace_hdr *)
6708c2ecf20Sopenharmony_ci		fc_trace_entries.page_offset[fc_trace_entries.wr_idx];
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	fc_trace_entries.wr_idx++;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	if (fc_trace_entries.wr_idx >= fc_trace_max_entries)
6758c2ecf20Sopenharmony_ci		fc_trace_entries.wr_idx = 0;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (fc_trace_entries.wr_idx == fc_trace_entries.rd_idx) {
6788c2ecf20Sopenharmony_ci		fc_trace_entries.rd_idx++;
6798c2ecf20Sopenharmony_ci		if (fc_trace_entries.rd_idx >= fc_trace_max_entries)
6808c2ecf20Sopenharmony_ci			fc_trace_entries.rd_idx = 0;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	ktime_get_real_ts64(&fc_buf->time_stamp);
6848c2ecf20Sopenharmony_ci	fc_buf->host_no = host_no;
6858c2ecf20Sopenharmony_ci	fc_buf->frame_type = frame_type;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	fc_trace = (char *)FC_TRACE_ADDRESS(fc_buf);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/* During the receive path, we do not have eth hdr as well as fcoe hdr
6908c2ecf20Sopenharmony_ci	 * at trace entry point so we will stuff 0xff just to make it generic.
6918c2ecf20Sopenharmony_ci	 */
6928c2ecf20Sopenharmony_ci	if (frame_type == FNIC_FC_RECV) {
6938c2ecf20Sopenharmony_ci		eth_fcoe_hdr_len = sizeof(struct ethhdr) +
6948c2ecf20Sopenharmony_ci					sizeof(struct fcoe_hdr);
6958c2ecf20Sopenharmony_ci		memset((char *)fc_trace, 0xff, eth_fcoe_hdr_len);
6968c2ecf20Sopenharmony_ci		/* Copy the rest of data frame */
6978c2ecf20Sopenharmony_ci		memcpy((char *)(fc_trace + eth_fcoe_hdr_len), (void *)frame,
6988c2ecf20Sopenharmony_ci		min_t(u8, fc_trc_frame_len,
6998c2ecf20Sopenharmony_ci			(u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE
7008c2ecf20Sopenharmony_ci						- eth_fcoe_hdr_len)));
7018c2ecf20Sopenharmony_ci	} else {
7028c2ecf20Sopenharmony_ci		memcpy((char *)fc_trace, (void *)frame,
7038c2ecf20Sopenharmony_ci		min_t(u8, fc_trc_frame_len,
7048c2ecf20Sopenharmony_ci			(u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE)));
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Store the actual received length */
7088c2ecf20Sopenharmony_ci	fc_buf->frame_len = fc_trc_frame_len;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&fnic_fc_trace_lock, flags);
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/*
7158c2ecf20Sopenharmony_ci * fnic_fc_ctlr_get_trace_data: Copy trace buffer to a memory file
7168c2ecf20Sopenharmony_ci * Passed parameter:
7178c2ecf20Sopenharmony_ci *       @fnic_dbgfs_t: pointer to debugfs trace buffer
7188c2ecf20Sopenharmony_ci *       rdata_flag: 1 => Unformated file
7198c2ecf20Sopenharmony_ci *                   0 => formated file
7208c2ecf20Sopenharmony_ci * Description:
7218c2ecf20Sopenharmony_ci *       This routine will copy the trace data to memory file with
7228c2ecf20Sopenharmony_ci *       proper formatting and also copy to another memory
7238c2ecf20Sopenharmony_ci *       file without formatting for further procesing.
7248c2ecf20Sopenharmony_ci * Retrun Value:
7258c2ecf20Sopenharmony_ci *       Number of bytes that were dumped into fnic_dbgfs_t
7268c2ecf20Sopenharmony_ci */
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ciint fnic_fc_trace_get_data(fnic_dbgfs_t *fnic_dbgfs_prt, u8 rdata_flag)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	int rd_idx, wr_idx;
7318c2ecf20Sopenharmony_ci	unsigned long flags;
7328c2ecf20Sopenharmony_ci	int len = 0, j;
7338c2ecf20Sopenharmony_ci	struct fc_trace_hdr *tdata;
7348c2ecf20Sopenharmony_ci	char *fc_trace;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	spin_lock_irqsave(&fnic_fc_trace_lock, flags);
7378c2ecf20Sopenharmony_ci	if (fc_trace_entries.wr_idx == fc_trace_entries.rd_idx) {
7388c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&fnic_fc_trace_lock, flags);
7398c2ecf20Sopenharmony_ci		pr_info("fnic: Buffer is empty\n");
7408c2ecf20Sopenharmony_ci		return 0;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	rd_idx = fc_trace_entries.rd_idx;
7438c2ecf20Sopenharmony_ci	wr_idx = fc_trace_entries.wr_idx;
7448c2ecf20Sopenharmony_ci	if (rdata_flag == 0) {
7458c2ecf20Sopenharmony_ci		len += scnprintf(fnic_dbgfs_prt->buffer + len,
7468c2ecf20Sopenharmony_ci			(fnic_fc_trace_max_pages * PAGE_SIZE * 3) - len,
7478c2ecf20Sopenharmony_ci			"Time Stamp (UTC)\t\t"
7488c2ecf20Sopenharmony_ci			"Host No:   F Type:  len:     FCoE_FRAME:\n");
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	while (rd_idx != wr_idx) {
7528c2ecf20Sopenharmony_ci		tdata = (struct fc_trace_hdr *)
7538c2ecf20Sopenharmony_ci			fc_trace_entries.page_offset[rd_idx];
7548c2ecf20Sopenharmony_ci		if (!tdata) {
7558c2ecf20Sopenharmony_ci			pr_info("fnic: Rd data is NULL\n");
7568c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&fnic_fc_trace_lock, flags);
7578c2ecf20Sopenharmony_ci			return 0;
7588c2ecf20Sopenharmony_ci		}
7598c2ecf20Sopenharmony_ci		if (rdata_flag == 0) {
7608c2ecf20Sopenharmony_ci			copy_and_format_trace_data(tdata,
7618c2ecf20Sopenharmony_ci				fnic_dbgfs_prt, &len, rdata_flag);
7628c2ecf20Sopenharmony_ci		} else {
7638c2ecf20Sopenharmony_ci			fc_trace = (char *)tdata;
7648c2ecf20Sopenharmony_ci			for (j = 0; j < FC_TRC_SIZE_BYTES; j++) {
7658c2ecf20Sopenharmony_ci				len += scnprintf(fnic_dbgfs_prt->buffer + len,
7668c2ecf20Sopenharmony_ci				(fnic_fc_trace_max_pages * PAGE_SIZE * 3)
7678c2ecf20Sopenharmony_ci				- len, "%02x", fc_trace[j] & 0xff);
7688c2ecf20Sopenharmony_ci			} /* for loop */
7698c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
7708c2ecf20Sopenharmony_ci				(fnic_fc_trace_max_pages * PAGE_SIZE * 3) - len,
7718c2ecf20Sopenharmony_ci				"\n");
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci		rd_idx++;
7748c2ecf20Sopenharmony_ci		if (rd_idx > (fc_trace_max_entries - 1))
7758c2ecf20Sopenharmony_ci			rd_idx = 0;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&fnic_fc_trace_lock, flags);
7798c2ecf20Sopenharmony_ci	return len;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci/*
7838c2ecf20Sopenharmony_ci * copy_and_format_trace_data: Copy formatted data to char * buffer
7848c2ecf20Sopenharmony_ci * Passed Parameter:
7858c2ecf20Sopenharmony_ci *      @fc_trace_hdr_t: pointer to trace data
7868c2ecf20Sopenharmony_ci *      @fnic_dbgfs_t: pointer to debugfs trace buffer
7878c2ecf20Sopenharmony_ci *      @orig_len: pointer to len
7888c2ecf20Sopenharmony_ci *      rdata_flag: 0 => Formated file, 1 => Unformated file
7898c2ecf20Sopenharmony_ci * Description:
7908c2ecf20Sopenharmony_ci *      This routine will format and copy the passed trace data
7918c2ecf20Sopenharmony_ci *      for formated file or unformated file accordingly.
7928c2ecf20Sopenharmony_ci */
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_civoid copy_and_format_trace_data(struct fc_trace_hdr *tdata,
7958c2ecf20Sopenharmony_ci				fnic_dbgfs_t *fnic_dbgfs_prt, int *orig_len,
7968c2ecf20Sopenharmony_ci				u8 rdata_flag)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct tm tm;
7998c2ecf20Sopenharmony_ci	int j, i = 1, len;
8008c2ecf20Sopenharmony_ci	char *fc_trace, *fmt;
8018c2ecf20Sopenharmony_ci	int ethhdr_len = sizeof(struct ethhdr) - 1;
8028c2ecf20Sopenharmony_ci	int fcoehdr_len = sizeof(struct fcoe_hdr);
8038c2ecf20Sopenharmony_ci	int fchdr_len = sizeof(struct fc_frame_header);
8048c2ecf20Sopenharmony_ci	int max_size = fnic_fc_trace_max_pages * PAGE_SIZE * 3;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	tdata->frame_type = tdata->frame_type & 0x7F;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	len = *orig_len;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	time64_to_tm(tdata->time_stamp.tv_sec, 0, &tm);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	fmt = "%02d:%02d:%04ld %02d:%02d:%02d.%09lu ns%8x       %c%8x\t";
8138c2ecf20Sopenharmony_ci	len += scnprintf(fnic_dbgfs_prt->buffer + len,
8148c2ecf20Sopenharmony_ci		max_size - len,
8158c2ecf20Sopenharmony_ci		fmt,
8168c2ecf20Sopenharmony_ci		tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900,
8178c2ecf20Sopenharmony_ci		tm.tm_hour, tm.tm_min, tm.tm_sec,
8188c2ecf20Sopenharmony_ci		tdata->time_stamp.tv_nsec, tdata->host_no,
8198c2ecf20Sopenharmony_ci		tdata->frame_type, tdata->frame_len);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	fc_trace = (char *)FC_TRACE_ADDRESS(tdata);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	for (j = 0; j < min_t(u8, tdata->frame_len,
8248c2ecf20Sopenharmony_ci		(u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE)); j++) {
8258c2ecf20Sopenharmony_ci		if (tdata->frame_type == FNIC_FC_LE) {
8268c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
8278c2ecf20Sopenharmony_ci				max_size - len, "%c", fc_trace[j]);
8288c2ecf20Sopenharmony_ci		} else {
8298c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
8308c2ecf20Sopenharmony_ci				max_size - len, "%02x", fc_trace[j] & 0xff);
8318c2ecf20Sopenharmony_ci			len += scnprintf(fnic_dbgfs_prt->buffer + len,
8328c2ecf20Sopenharmony_ci				max_size - len, " ");
8338c2ecf20Sopenharmony_ci			if (j == ethhdr_len ||
8348c2ecf20Sopenharmony_ci				j == ethhdr_len + fcoehdr_len ||
8358c2ecf20Sopenharmony_ci				j == ethhdr_len + fcoehdr_len + fchdr_len ||
8368c2ecf20Sopenharmony_ci				(i > 3 && j%fchdr_len == 0)) {
8378c2ecf20Sopenharmony_ci				len += scnprintf(fnic_dbgfs_prt->buffer
8388c2ecf20Sopenharmony_ci					+ len, max_size - len,
8398c2ecf20Sopenharmony_ci					"\n\t\t\t\t\t\t\t\t");
8408c2ecf20Sopenharmony_ci				i++;
8418c2ecf20Sopenharmony_ci			}
8428c2ecf20Sopenharmony_ci		} /* end of else*/
8438c2ecf20Sopenharmony_ci	} /* End of for loop*/
8448c2ecf20Sopenharmony_ci	len += scnprintf(fnic_dbgfs_prt->buffer + len,
8458c2ecf20Sopenharmony_ci		max_size - len, "\n");
8468c2ecf20Sopenharmony_ci	*orig_len = len;
8478c2ecf20Sopenharmony_ci}
848