xref: /OK3568_Linux_fs/kernel/drivers/scsi/snic/snic_trc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you may redistribute it and/or modify
5*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun  * the Free Software Foundation; version 2 of the License.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15*4882a593Smuzhiyun  * SOFTWARE.
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/mempool.h>
20*4882a593Smuzhiyun #include <linux/errno.h>
21*4882a593Smuzhiyun #include <linux/vmalloc.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "snic_io.h"
24*4882a593Smuzhiyun #include "snic.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  * snic_get_trc_buf : Allocates a trace record and returns.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun struct snic_trc_data *
snic_get_trc_buf(void)30*4882a593Smuzhiyun snic_get_trc_buf(void)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	struct snic_trc *trc = &snic_glob->trc;
33*4882a593Smuzhiyun 	struct snic_trc_data *td = NULL;
34*4882a593Smuzhiyun 	unsigned long flags;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	spin_lock_irqsave(&trc->lock, flags);
37*4882a593Smuzhiyun 	td = &trc->buf[trc->wr_idx];
38*4882a593Smuzhiyun 	trc->wr_idx++;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (trc->wr_idx == trc->max_idx)
41*4882a593Smuzhiyun 		trc->wr_idx = 0;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (trc->wr_idx != trc->rd_idx) {
44*4882a593Smuzhiyun 		spin_unlock_irqrestore(&trc->lock, flags);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 		goto end;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	trc->rd_idx++;
50*4882a593Smuzhiyun 	if (trc->rd_idx == trc->max_idx)
51*4882a593Smuzhiyun 		trc->rd_idx = 0;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	td->ts = 0;	/* Marker for checking the record, for complete data*/
54*4882a593Smuzhiyun 	spin_unlock_irqrestore(&trc->lock, flags);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun end:
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return td;
59*4882a593Smuzhiyun } /* end of snic_get_trc_buf */
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun  * snic_fmt_trc_data : Formats trace data for printing.
63*4882a593Smuzhiyun  */
64*4882a593Smuzhiyun static int
snic_fmt_trc_data(struct snic_trc_data * td,char * buf,int buf_sz)65*4882a593Smuzhiyun snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	int len = 0;
68*4882a593Smuzhiyun 	struct timespec64 tmspec;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	jiffies_to_timespec64(td->ts, &tmspec);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	len += snprintf(buf, buf_sz,
73*4882a593Smuzhiyun 			"%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n",
74*4882a593Smuzhiyun 			tmspec.tv_sec,
75*4882a593Smuzhiyun 			tmspec.tv_nsec,
76*4882a593Smuzhiyun 			td->fn,
77*4882a593Smuzhiyun 			td->hno,
78*4882a593Smuzhiyun 			td->tag,
79*4882a593Smuzhiyun 			td->data[0], td->data[1], td->data[2], td->data[3],
80*4882a593Smuzhiyun 			td->data[4]);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	return len;
83*4882a593Smuzhiyun } /* end of snic_fmt_trc_data */
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun  * snic_get_trc_data : Returns a formatted trace buffer.
87*4882a593Smuzhiyun  */
88*4882a593Smuzhiyun int
snic_get_trc_data(char * buf,int buf_sz)89*4882a593Smuzhiyun snic_get_trc_data(char *buf, int buf_sz)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct snic_trc_data *td = NULL;
92*4882a593Smuzhiyun 	struct snic_trc *trc = &snic_glob->trc;
93*4882a593Smuzhiyun 	unsigned long flags;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	spin_lock_irqsave(&trc->lock, flags);
96*4882a593Smuzhiyun 	if (trc->rd_idx == trc->wr_idx) {
97*4882a593Smuzhiyun 		spin_unlock_irqrestore(&trc->lock, flags);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		return -1;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 	td = &trc->buf[trc->rd_idx];
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (td->ts == 0) {
104*4882a593Smuzhiyun 		/* write in progress. */
105*4882a593Smuzhiyun 		spin_unlock_irqrestore(&trc->lock, flags);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 		return -1;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	trc->rd_idx++;
111*4882a593Smuzhiyun 	if (trc->rd_idx == trc->max_idx)
112*4882a593Smuzhiyun 		trc->rd_idx = 0;
113*4882a593Smuzhiyun 	spin_unlock_irqrestore(&trc->lock, flags);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return snic_fmt_trc_data(td, buf, buf_sz);
116*4882a593Smuzhiyun } /* end of snic_get_trc_data */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /*
119*4882a593Smuzhiyun  * snic_trc_init() : Configures Trace Functionality for snic.
120*4882a593Smuzhiyun  */
121*4882a593Smuzhiyun int
snic_trc_init(void)122*4882a593Smuzhiyun snic_trc_init(void)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	struct snic_trc *trc = &snic_glob->trc;
125*4882a593Smuzhiyun 	void *tbuf = NULL;
126*4882a593Smuzhiyun 	int tbuf_sz = 0, ret;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	tbuf_sz = (snic_trace_max_pages * PAGE_SIZE);
129*4882a593Smuzhiyun 	tbuf = vzalloc(tbuf_sz);
130*4882a593Smuzhiyun 	if (!tbuf) {
131*4882a593Smuzhiyun 		SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz);
132*4882a593Smuzhiyun 		SNIC_ERR("Trace Facility not enabled.\n");
133*4882a593Smuzhiyun 		ret = -ENOMEM;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		return ret;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	trc->buf = (struct snic_trc_data *) tbuf;
139*4882a593Smuzhiyun 	spin_lock_init(&trc->lock);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	snic_trc_debugfs_init();
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ);
144*4882a593Smuzhiyun 	trc->rd_idx = trc->wr_idx = 0;
145*4882a593Smuzhiyun 	trc->enable = true;
146*4882a593Smuzhiyun 	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n",
147*4882a593Smuzhiyun 		  tbuf_sz / PAGE_SIZE);
148*4882a593Smuzhiyun 	ret = 0;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return ret;
151*4882a593Smuzhiyun } /* end of snic_trc_init */
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun  * snic_trc_free : Releases the trace buffer and disables the tracing.
155*4882a593Smuzhiyun  */
156*4882a593Smuzhiyun void
snic_trc_free(void)157*4882a593Smuzhiyun snic_trc_free(void)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	struct snic_trc *trc = &snic_glob->trc;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	trc->enable = false;
162*4882a593Smuzhiyun 	snic_trc_debugfs_term();
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (trc->buf) {
165*4882a593Smuzhiyun 		vfree(trc->buf);
166*4882a593Smuzhiyun 		trc->buf = NULL;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	SNIC_INFO("Trace Facility Disabled.\n");
170*4882a593Smuzhiyun } /* end of snic_trc_free */
171