1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * linux/drivers/scsi/esas2r/esas2r_log.c
3*4882a593Smuzhiyun * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2001-2013 ATTO Technology, Inc.
6*4882a593Smuzhiyun * (mailto:linuxdrivers@attotech.com)
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
9*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License
10*4882a593Smuzhiyun * as published by the Free Software Foundation; either version 2
11*4882a593Smuzhiyun * of the License, or (at your option) any later version.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun * GNU General Public License for more details.
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * NO WARRANTY
19*4882a593Smuzhiyun * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20*4882a593Smuzhiyun * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21*4882a593Smuzhiyun * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22*4882a593Smuzhiyun * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23*4882a593Smuzhiyun * solely responsible for determining the appropriateness of using and
24*4882a593Smuzhiyun * distributing the Program and assumes all risks associated with its
25*4882a593Smuzhiyun * exercise of rights under this Agreement, including but not limited to
26*4882a593Smuzhiyun * the risks and costs of program errors, damage to or loss of data,
27*4882a593Smuzhiyun * programs or equipment, and unavailability or interruption of operations.
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * DISCLAIMER OF LIABILITY
30*4882a593Smuzhiyun * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31*4882a593Smuzhiyun * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32*4882a593Smuzhiyun * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33*4882a593Smuzhiyun * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34*4882a593Smuzhiyun * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35*4882a593Smuzhiyun * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36*4882a593Smuzhiyun * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37*4882a593Smuzhiyun *
38*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
39*4882a593Smuzhiyun * along with this program; if not, write to the Free Software
40*4882a593Smuzhiyun * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
41*4882a593Smuzhiyun * USA.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include "esas2r.h"
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun * this module within the driver is tasked with providing logging functionality.
48*4882a593Smuzhiyun * the event_log_level module parameter controls the level of messages that are
49*4882a593Smuzhiyun * written to the system log. the default level of messages that are written
50*4882a593Smuzhiyun * are critical and warning messages. if other types of messages are desired,
51*4882a593Smuzhiyun * one simply needs to load the module with the correct value for the
52*4882a593Smuzhiyun * event_log_level module parameter. for example:
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * insmod <module> event_log_level=1
55*4882a593Smuzhiyun *
56*4882a593Smuzhiyun * will load the module and only critical events will be written by this module
57*4882a593Smuzhiyun * to the system log. if critical, warning, and information-level messages are
58*4882a593Smuzhiyun * desired, the correct value for the event_log_level module parameter
59*4882a593Smuzhiyun * would be as follows:
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * insmod <module> event_log_level=3
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #define EVENT_LOG_BUFF_SIZE 1024
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static long event_log_level = ESAS2R_LOG_DFLT;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun module_param(event_log_level, long, S_IRUGO | S_IRUSR);
69*4882a593Smuzhiyun MODULE_PARM_DESC(event_log_level,
70*4882a593Smuzhiyun "Specifies the level of events to report to the system log. Critical and warning level events are logged by default.");
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* A shared buffer to use for formatting messages. */
73*4882a593Smuzhiyun static char event_buffer[EVENT_LOG_BUFF_SIZE];
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* A lock to protect the shared buffer used for formatting messages. */
76*4882a593Smuzhiyun static DEFINE_SPINLOCK(event_buffer_lock);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun * translates an esas2r-defined logging event level to a kernel logging level.
80*4882a593Smuzhiyun *
81*4882a593Smuzhiyun * @param [in] level the esas2r-defined logging event level to translate
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * @return the corresponding kernel logging level.
84*4882a593Smuzhiyun */
translate_esas2r_event_level_to_kernel(const long level)85*4882a593Smuzhiyun static const char *translate_esas2r_event_level_to_kernel(const long level)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun switch (level) {
88*4882a593Smuzhiyun case ESAS2R_LOG_CRIT:
89*4882a593Smuzhiyun return KERN_CRIT;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun case ESAS2R_LOG_WARN:
92*4882a593Smuzhiyun return KERN_WARNING;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun case ESAS2R_LOG_INFO:
95*4882a593Smuzhiyun return KERN_INFO;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun case ESAS2R_LOG_DEBG:
98*4882a593Smuzhiyun case ESAS2R_LOG_TRCE:
99*4882a593Smuzhiyun default:
100*4882a593Smuzhiyun return KERN_DEBUG;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun * the master logging function. this function will format the message as
106*4882a593Smuzhiyun * outlined by the formatting string, the input device information and the
107*4882a593Smuzhiyun * substitution arguments and output the resulting string to the system log.
108*4882a593Smuzhiyun *
109*4882a593Smuzhiyun * @param [in] level the event log level of the message
110*4882a593Smuzhiyun * @param [in] dev the device information
111*4882a593Smuzhiyun * @param [in] format the formatting string for the message
112*4882a593Smuzhiyun * @param [in] args the substition arguments to the formatting string
113*4882a593Smuzhiyun *
114*4882a593Smuzhiyun * @return 0 on success, or -1 if an error occurred.
115*4882a593Smuzhiyun */
esas2r_log_master(const long level,const struct device * dev,const char * format,va_list args)116*4882a593Smuzhiyun static int esas2r_log_master(const long level,
117*4882a593Smuzhiyun const struct device *dev,
118*4882a593Smuzhiyun const char *format,
119*4882a593Smuzhiyun va_list args)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun if (level <= event_log_level) {
122*4882a593Smuzhiyun unsigned long flags = 0;
123*4882a593Smuzhiyun int retval = 0;
124*4882a593Smuzhiyun char *buffer = event_buffer;
125*4882a593Smuzhiyun size_t buflen = EVENT_LOG_BUFF_SIZE;
126*4882a593Smuzhiyun const char *fmt_nodev = "%s%s: ";
127*4882a593Smuzhiyun const char *fmt_dev = "%s%s [%s, %s, %s]";
128*4882a593Smuzhiyun const char *slevel =
129*4882a593Smuzhiyun translate_esas2r_event_level_to_kernel(level);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun spin_lock_irqsave(&event_buffer_lock, flags);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun memset(buffer, 0, buflen);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun * format the level onto the beginning of the string and do
137*4882a593Smuzhiyun * some pointer arithmetic to move the pointer to the point
138*4882a593Smuzhiyun * where the actual message can be inserted.
139*4882a593Smuzhiyun */
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (dev == NULL) {
142*4882a593Smuzhiyun snprintf(buffer, buflen, fmt_nodev, slevel,
143*4882a593Smuzhiyun ESAS2R_DRVR_NAME);
144*4882a593Smuzhiyun } else {
145*4882a593Smuzhiyun snprintf(buffer, buflen, fmt_dev, slevel,
146*4882a593Smuzhiyun ESAS2R_DRVR_NAME,
147*4882a593Smuzhiyun (dev->driver ? dev->driver->name : "unknown"),
148*4882a593Smuzhiyun (dev->bus ? dev->bus->name : "unknown"),
149*4882a593Smuzhiyun dev_name(dev));
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun buffer += strlen(event_buffer);
153*4882a593Smuzhiyun buflen -= strlen(event_buffer);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun retval = vsnprintf(buffer, buflen, format, args);
156*4882a593Smuzhiyun if (retval < 0) {
157*4882a593Smuzhiyun spin_unlock_irqrestore(&event_buffer_lock, flags);
158*4882a593Smuzhiyun return -1;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /*
162*4882a593Smuzhiyun * Put a line break at the end of the formatted string so that
163*4882a593Smuzhiyun * we don't wind up with run-on messages.
164*4882a593Smuzhiyun */
165*4882a593Smuzhiyun printk("%s\n", event_buffer);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun spin_unlock_irqrestore(&event_buffer_lock, flags);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun * formats and logs a message to the system log.
175*4882a593Smuzhiyun *
176*4882a593Smuzhiyun * @param [in] level the event level of the message
177*4882a593Smuzhiyun * @param [in] format the formating string for the message
178*4882a593Smuzhiyun * @param [in] ... the substitution arguments to the formatting string
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * @return 0 on success, or -1 if an error occurred.
181*4882a593Smuzhiyun */
esas2r_log(const long level,const char * format,...)182*4882a593Smuzhiyun int esas2r_log(const long level, const char *format, ...)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun int retval = 0;
185*4882a593Smuzhiyun va_list args;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun va_start(args, format);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun retval = esas2r_log_master(level, NULL, format, args);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun va_end(args);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun return retval;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /*
197*4882a593Smuzhiyun * formats and logs a message to the system log. this message will include
198*4882a593Smuzhiyun * device information.
199*4882a593Smuzhiyun *
200*4882a593Smuzhiyun * @param [in] level the event level of the message
201*4882a593Smuzhiyun * @param [in] dev the device information
202*4882a593Smuzhiyun * @param [in] format the formatting string for the message
203*4882a593Smuzhiyun * @param [in] ... the substitution arguments to the formatting string
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * @return 0 on success, or -1 if an error occurred.
206*4882a593Smuzhiyun */
esas2r_log_dev(const long level,const struct device * dev,const char * format,...)207*4882a593Smuzhiyun int esas2r_log_dev(const long level,
208*4882a593Smuzhiyun const struct device *dev,
209*4882a593Smuzhiyun const char *format,
210*4882a593Smuzhiyun ...)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun int retval = 0;
213*4882a593Smuzhiyun va_list args;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun va_start(args, format);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun retval = esas2r_log_master(level, dev, format, args);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun va_end(args);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return retval;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /*
225*4882a593Smuzhiyun * formats and logs a message to the system log. this message will include
226*4882a593Smuzhiyun * device information.
227*4882a593Smuzhiyun *
228*4882a593Smuzhiyun * @param [in] level the event level of the message
229*4882a593Smuzhiyun * @param [in] buf
230*4882a593Smuzhiyun * @param [in] len
231*4882a593Smuzhiyun *
232*4882a593Smuzhiyun * @return 0 on success, or -1 if an error occurred.
233*4882a593Smuzhiyun */
esas2r_log_hexdump(const long level,const void * buf,size_t len)234*4882a593Smuzhiyun int esas2r_log_hexdump(const long level,
235*4882a593Smuzhiyun const void *buf,
236*4882a593Smuzhiyun size_t len)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun if (level <= event_log_level) {
239*4882a593Smuzhiyun print_hex_dump(translate_esas2r_event_level_to_kernel(level),
240*4882a593Smuzhiyun "", DUMP_PREFIX_OFFSET, 16, 1, buf,
241*4882a593Smuzhiyun len, true);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun return 1;
245*4882a593Smuzhiyun }
246