Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/scsi/esas2r/esas2r_log.c
0003  *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
0004  *
0005  *  Copyright (c) 2001-2013 ATTO Technology, Inc.
0006  *  (mailto:linuxdrivers@attotech.com)
0007  *
0008  * This program is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU General Public License
0010  * as published by the Free Software Foundation; either version 2
0011  * of the License, or (at your option) any later version.
0012  *
0013  * This program is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016  * GNU General Public License for more details.
0017  *
0018  * NO WARRANTY
0019  * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
0020  * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
0021  * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
0022  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
0023  * solely responsible for determining the appropriateness of using and
0024  * distributing the Program and assumes all risks associated with its
0025  * exercise of rights under this Agreement, including but not limited to
0026  * the risks and costs of program errors, damage to or loss of data,
0027  * programs or equipment, and unavailability or interruption of operations.
0028  *
0029  * DISCLAIMER OF LIABILITY
0030  * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
0031  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0032  * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
0033  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
0034  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
0035  * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
0036  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
0037  *
0038  * You should have received a copy of the GNU General Public License
0039  * along with this program; if not, write to the Free Software
0040  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
0041  * USA.
0042  */
0043 
0044 #include "esas2r.h"
0045 
0046 /*
0047  * this module within the driver is tasked with providing logging functionality.
0048  * the event_log_level module parameter controls the level of messages that are
0049  * written to the system log.  the default level of messages that are written
0050  * are critical and warning messages.  if other types of messages are desired,
0051  * one simply needs to load the module with the correct value for the
0052  * event_log_level module parameter.  for example:
0053  *
0054  * insmod <module> event_log_level=1
0055  *
0056  * will load the module and only critical events will be written by this module
0057  * to the system log.  if critical, warning, and information-level messages are
0058  * desired, the correct value for the event_log_level module parameter
0059  * would be as follows:
0060  *
0061  * insmod <module> event_log_level=3
0062  */
0063 
0064 #define EVENT_LOG_BUFF_SIZE 1024
0065 
0066 static long event_log_level = ESAS2R_LOG_DFLT;
0067 
0068 module_param(event_log_level, long, S_IRUGO | S_IRUSR);
0069 MODULE_PARM_DESC(event_log_level,
0070          "Specifies the level of events to report to the system log.  Critical and warning level events are logged by default.");
0071 
0072 /* A shared buffer to use for formatting messages. */
0073 static char event_buffer[EVENT_LOG_BUFF_SIZE];
0074 
0075 /* A lock to protect the shared buffer used for formatting messages. */
0076 static DEFINE_SPINLOCK(event_buffer_lock);
0077 
0078 /*
0079  * translates an esas2r-defined logging event level to a kernel logging level.
0080  *
0081  * @param [in] level the esas2r-defined logging event level to translate
0082  *
0083  * @return the corresponding kernel logging level.
0084  */
0085 static const char *translate_esas2r_event_level_to_kernel(const long level)
0086 {
0087     switch (level) {
0088     case ESAS2R_LOG_CRIT:
0089         return KERN_CRIT;
0090 
0091     case ESAS2R_LOG_WARN:
0092         return KERN_WARNING;
0093 
0094     case ESAS2R_LOG_INFO:
0095         return KERN_INFO;
0096 
0097     case ESAS2R_LOG_DEBG:
0098     case ESAS2R_LOG_TRCE:
0099     default:
0100         return KERN_DEBUG;
0101     }
0102 }
0103 
0104 #pragma GCC diagnostic push
0105 #ifndef __clang__
0106 #pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
0107 #endif
0108 
0109 /*
0110  * the master logging function.  this function will format the message as
0111  * outlined by the formatting string, the input device information and the
0112  * substitution arguments and output the resulting string to the system log.
0113  *
0114  * @param [in] level  the event log level of the message
0115  * @param [in] dev    the device information
0116  * @param [in] format the formatting string for the message
0117  * @param [in] args   the substition arguments to the formatting string
0118  *
0119  * @return 0 on success, or -1 if an error occurred.
0120  */
0121 static int esas2r_log_master(const long level,
0122                  const struct device *dev,
0123                  const char *format,
0124                  va_list args)
0125 {
0126     if (level <= event_log_level) {
0127         unsigned long flags = 0;
0128         int retval = 0;
0129         char *buffer = event_buffer;
0130         size_t buflen = EVENT_LOG_BUFF_SIZE;
0131         const char *fmt_nodev = "%s%s: ";
0132         const char *fmt_dev = "%s%s [%s, %s, %s]";
0133         const char *slevel =
0134             translate_esas2r_event_level_to_kernel(level);
0135 
0136         spin_lock_irqsave(&event_buffer_lock, flags);
0137 
0138         memset(buffer, 0, buflen);
0139 
0140         /*
0141          * format the level onto the beginning of the string and do
0142          * some pointer arithmetic to move the pointer to the point
0143          * where the actual message can be inserted.
0144          */
0145 
0146         if (dev == NULL) {
0147             snprintf(buffer, buflen, fmt_nodev, slevel,
0148                  ESAS2R_DRVR_NAME);
0149         } else {
0150             snprintf(buffer, buflen, fmt_dev, slevel,
0151                  ESAS2R_DRVR_NAME,
0152                  (dev->driver ? dev->driver->name : "unknown"),
0153                  (dev->bus ? dev->bus->name : "unknown"),
0154                  dev_name(dev));
0155         }
0156 
0157         buffer += strlen(event_buffer);
0158         buflen -= strlen(event_buffer);
0159 
0160         retval = vsnprintf(buffer, buflen, format, args);
0161         if (retval < 0) {
0162             spin_unlock_irqrestore(&event_buffer_lock, flags);
0163             return -1;
0164         }
0165 
0166         /*
0167          * Put a line break at the end of the formatted string so that
0168          * we don't wind up with run-on messages.
0169          */
0170         printk("%s\n", event_buffer);
0171 
0172         spin_unlock_irqrestore(&event_buffer_lock, flags);
0173     }
0174 
0175     return 0;
0176 }
0177 
0178 #pragma GCC diagnostic pop
0179 
0180 /*
0181  * formats and logs a message to the system log.
0182  *
0183  * @param [in] level  the event level of the message
0184  * @param [in] format the formating string for the message
0185  * @param [in] ...    the substitution arguments to the formatting string
0186  *
0187  * @return 0 on success, or -1 if an error occurred.
0188  */
0189 int esas2r_log(const long level, const char *format, ...)
0190 {
0191     int retval = 0;
0192     va_list args;
0193 
0194     va_start(args, format);
0195 
0196     retval = esas2r_log_master(level, NULL, format, args);
0197 
0198     va_end(args);
0199 
0200     return retval;
0201 }
0202 
0203 /*
0204  * formats and logs a message to the system log.  this message will include
0205  * device information.
0206  *
0207  * @param [in] level   the event level of the message
0208  * @param [in] dev     the device information
0209  * @param [in] format  the formatting string for the message
0210  * @param [in] ...     the substitution arguments to the formatting string
0211  *
0212  * @return 0 on success, or -1 if an error occurred.
0213  */
0214 int esas2r_log_dev(const long level,
0215            const struct device *dev,
0216            const char *format,
0217            ...)
0218 {
0219     int retval = 0;
0220     va_list args;
0221 
0222     va_start(args, format);
0223 
0224     retval = esas2r_log_master(level, dev, format, args);
0225 
0226     va_end(args);
0227 
0228     return retval;
0229 }
0230 
0231 /*
0232  * formats and logs a message to the system log.  this message will include
0233  * device information.
0234  *
0235  * @param [in] level   the event level of the message
0236  * @param [in] buf
0237  * @param [in] len
0238  *
0239  * @return 0 on success, or -1 if an error occurred.
0240  */
0241 int esas2r_log_hexdump(const long level,
0242                const void *buf,
0243                size_t len)
0244 {
0245     if (level <= event_log_level) {
0246         print_hex_dump(translate_esas2r_event_level_to_kernel(level),
0247                    "", DUMP_PREFIX_OFFSET, 16, 1, buf,
0248                    len, true);
0249     }
0250 
0251     return 1;
0252 }