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