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 memset(buffer, 0, buflen); 134 135 /* 136 * format the level onto the beginning of the string and do 137 * some pointer arithmetic to move the pointer to the point 138 * where the actual message can be inserted. 139 */ 140 141 if (dev == NULL) { 142 snprintf(buffer, buflen, fmt_nodev, slevel, 143 ESAS2R_DRVR_NAME); 144 } else { 145 snprintf(buffer, buflen, fmt_dev, slevel, 146 ESAS2R_DRVR_NAME, 147 (dev->driver ? dev->driver->name : "unknown"), 148 (dev->bus ? dev->bus->name : "unknown"), 149 dev_name(dev)); 150 } 151 152 buffer += strlen(event_buffer); 153 buflen -= strlen(event_buffer); 154 155 retval = vsnprintf(buffer, buflen, format, args); 156 if (retval < 0) { 157 spin_unlock_irqrestore(&event_buffer_lock, flags); 158 return -1; 159 } 160 161 /* 162 * Put a line break at the end of the formatted string so that 163 * we don't wind up with run-on messages. 164 */ 165 printk("%s\n", event_buffer); 166 167 spin_unlock_irqrestore(&event_buffer_lock, flags); 168 } 169 170 return 0; 171 } 172 173 /* 174 * formats and logs a message to the system log. 175 * 176 * @param [in] level the event level of the message 177 * @param [in] format the formating string for the message 178 * @param [in] ... the substitution arguments to the formatting string 179 * 180 * @return 0 on success, or -1 if an error occurred. 181 */ 182 int esas2r_log(const long level, const char *format, ...) 183 { 184 int retval = 0; 185 va_list args; 186 187 va_start(args, format); 188 189 retval = esas2r_log_master(level, NULL, format, args); 190 191 va_end(args); 192 193 return retval; 194 } 195 196 /* 197 * formats and logs a message to the system log. this message will include 198 * device information. 199 * 200 * @param [in] level the event level of the message 201 * @param [in] dev the device information 202 * @param [in] format the formatting string for the message 203 * @param [in] ... the substitution arguments to the formatting string 204 * 205 * @return 0 on success, or -1 if an error occurred. 206 */ 207 int esas2r_log_dev(const long level, 208 const struct device *dev, 209 const char *format, 210 ...) 211 { 212 int retval = 0; 213 va_list args; 214 215 va_start(args, format); 216 217 retval = esas2r_log_master(level, dev, format, args); 218 219 va_end(args); 220 221 return retval; 222 } 223 224 /* 225 * formats and logs a message to the system log. this message will include 226 * device information. 227 * 228 * @param [in] level the event level of the message 229 * @param [in] buf 230 * @param [in] len 231 * 232 * @return 0 on success, or -1 if an error occurred. 233 */ 234 int esas2r_log_hexdump(const long level, 235 const void *buf, 236 size_t len) 237 { 238 if (level <= event_log_level) { 239 print_hex_dump(translate_esas2r_event_level_to_kernel(level), 240 "", DUMP_PREFIX_OFFSET, 16, 1, buf, 241 len, true); 242 } 243 244 return 1; 245 } 246