18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/scsi/esas2r/esas2r_log.c 38c2ecf20Sopenharmony_ci * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2001-2013 ATTO Technology, Inc. 68c2ecf20Sopenharmony_ci * (mailto:linuxdrivers@attotech.com) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License 108c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2 118c2ecf20Sopenharmony_ci * of the License, or (at your option) any later version. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 148c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 168c2ecf20Sopenharmony_ci * GNU General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * NO WARRANTY 198c2ecf20Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 208c2ecf20Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 218c2ecf20Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 228c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 238c2ecf20Sopenharmony_ci * solely responsible for determining the appropriateness of using and 248c2ecf20Sopenharmony_ci * distributing the Program and assumes all risks associated with its 258c2ecf20Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to 268c2ecf20Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data, 278c2ecf20Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * DISCLAIMER OF LIABILITY 308c2ecf20Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 318c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 328c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 338c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 348c2ecf20Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 358c2ecf20Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 368c2ecf20Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 398c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 408c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 418c2ecf20Sopenharmony_ci * USA. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include "esas2r.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * this module within the driver is tasked with providing logging functionality. 488c2ecf20Sopenharmony_ci * the event_log_level module parameter controls the level of messages that are 498c2ecf20Sopenharmony_ci * written to the system log. the default level of messages that are written 508c2ecf20Sopenharmony_ci * are critical and warning messages. if other types of messages are desired, 518c2ecf20Sopenharmony_ci * one simply needs to load the module with the correct value for the 528c2ecf20Sopenharmony_ci * event_log_level module parameter. for example: 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * insmod <module> event_log_level=1 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * will load the module and only critical events will be written by this module 578c2ecf20Sopenharmony_ci * to the system log. if critical, warning, and information-level messages are 588c2ecf20Sopenharmony_ci * desired, the correct value for the event_log_level module parameter 598c2ecf20Sopenharmony_ci * would be as follows: 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * insmod <module> event_log_level=3 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define EVENT_LOG_BUFF_SIZE 1024 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic long event_log_level = ESAS2R_LOG_DFLT; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cimodule_param(event_log_level, long, S_IRUGO | S_IRUSR); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(event_log_level, 708c2ecf20Sopenharmony_ci "Specifies the level of events to report to the system log. Critical and warning level events are logged by default."); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* A shared buffer to use for formatting messages. */ 738c2ecf20Sopenharmony_cistatic char event_buffer[EVENT_LOG_BUFF_SIZE]; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* A lock to protect the shared buffer used for formatting messages. */ 768c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(event_buffer_lock); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * translates an esas2r-defined logging event level to a kernel logging level. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * @param [in] level the esas2r-defined logging event level to translate 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * @return the corresponding kernel logging level. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic const char *translate_esas2r_event_level_to_kernel(const long level) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci switch (level) { 888c2ecf20Sopenharmony_ci case ESAS2R_LOG_CRIT: 898c2ecf20Sopenharmony_ci return KERN_CRIT; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci case ESAS2R_LOG_WARN: 928c2ecf20Sopenharmony_ci return KERN_WARNING; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci case ESAS2R_LOG_INFO: 958c2ecf20Sopenharmony_ci return KERN_INFO; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci case ESAS2R_LOG_DEBG: 988c2ecf20Sopenharmony_ci case ESAS2R_LOG_TRCE: 998c2ecf20Sopenharmony_ci default: 1008c2ecf20Sopenharmony_ci return KERN_DEBUG; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * the master logging function. this function will format the message as 1068c2ecf20Sopenharmony_ci * outlined by the formatting string, the input device information and the 1078c2ecf20Sopenharmony_ci * substitution arguments and output the resulting string to the system log. 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * @param [in] level the event log level of the message 1108c2ecf20Sopenharmony_ci * @param [in] dev the device information 1118c2ecf20Sopenharmony_ci * @param [in] format the formatting string for the message 1128c2ecf20Sopenharmony_ci * @param [in] args the substition arguments to the formatting string 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * @return 0 on success, or -1 if an error occurred. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_cistatic int esas2r_log_master(const long level, 1178c2ecf20Sopenharmony_ci const struct device *dev, 1188c2ecf20Sopenharmony_ci const char *format, 1198c2ecf20Sopenharmony_ci va_list args) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if (level <= event_log_level) { 1228c2ecf20Sopenharmony_ci unsigned long flags = 0; 1238c2ecf20Sopenharmony_ci int retval = 0; 1248c2ecf20Sopenharmony_ci char *buffer = event_buffer; 1258c2ecf20Sopenharmony_ci size_t buflen = EVENT_LOG_BUFF_SIZE; 1268c2ecf20Sopenharmony_ci const char *fmt_nodev = "%s%s: "; 1278c2ecf20Sopenharmony_ci const char *fmt_dev = "%s%s [%s, %s, %s]"; 1288c2ecf20Sopenharmony_ci const char *slevel = 1298c2ecf20Sopenharmony_ci translate_esas2r_event_level_to_kernel(level); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci spin_lock_irqsave(&event_buffer_lock, flags); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci memset(buffer, 0, buflen); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * format the level onto the beginning of the string and do 1378c2ecf20Sopenharmony_ci * some pointer arithmetic to move the pointer to the point 1388c2ecf20Sopenharmony_ci * where the actual message can be inserted. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (dev == NULL) { 1428c2ecf20Sopenharmony_ci snprintf(buffer, buflen, fmt_nodev, slevel, 1438c2ecf20Sopenharmony_ci ESAS2R_DRVR_NAME); 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci snprintf(buffer, buflen, fmt_dev, slevel, 1468c2ecf20Sopenharmony_ci ESAS2R_DRVR_NAME, 1478c2ecf20Sopenharmony_ci (dev->driver ? dev->driver->name : "unknown"), 1488c2ecf20Sopenharmony_ci (dev->bus ? dev->bus->name : "unknown"), 1498c2ecf20Sopenharmony_ci dev_name(dev)); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci buffer += strlen(event_buffer); 1538c2ecf20Sopenharmony_ci buflen -= strlen(event_buffer); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci retval = vsnprintf(buffer, buflen, format, args); 1568c2ecf20Sopenharmony_ci if (retval < 0) { 1578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&event_buffer_lock, flags); 1588c2ecf20Sopenharmony_ci return -1; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * Put a line break at the end of the formatted string so that 1638c2ecf20Sopenharmony_ci * we don't wind up with run-on messages. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci printk("%s\n", event_buffer); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&event_buffer_lock, flags); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * formats and logs a message to the system log. 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * @param [in] level the event level of the message 1778c2ecf20Sopenharmony_ci * @param [in] format the formating string for the message 1788c2ecf20Sopenharmony_ci * @param [in] ... the substitution arguments to the formatting string 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * @return 0 on success, or -1 if an error occurred. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ciint esas2r_log(const long level, const char *format, ...) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int retval = 0; 1858c2ecf20Sopenharmony_ci va_list args; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci va_start(args, format); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci retval = esas2r_log_master(level, NULL, format, args); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci va_end(args); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return retval; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * formats and logs a message to the system log. this message will include 1988c2ecf20Sopenharmony_ci * device information. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * @param [in] level the event level of the message 2018c2ecf20Sopenharmony_ci * @param [in] dev the device information 2028c2ecf20Sopenharmony_ci * @param [in] format the formatting string for the message 2038c2ecf20Sopenharmony_ci * @param [in] ... the substitution arguments to the formatting string 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * @return 0 on success, or -1 if an error occurred. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ciint esas2r_log_dev(const long level, 2088c2ecf20Sopenharmony_ci const struct device *dev, 2098c2ecf20Sopenharmony_ci const char *format, 2108c2ecf20Sopenharmony_ci ...) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci int retval = 0; 2138c2ecf20Sopenharmony_ci va_list args; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci va_start(args, format); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci retval = esas2r_log_master(level, dev, format, args); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci va_end(args); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return retval; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * formats and logs a message to the system log. this message will include 2268c2ecf20Sopenharmony_ci * device information. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * @param [in] level the event level of the message 2298c2ecf20Sopenharmony_ci * @param [in] buf 2308c2ecf20Sopenharmony_ci * @param [in] len 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * @return 0 on success, or -1 if an error occurred. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ciint esas2r_log_hexdump(const long level, 2358c2ecf20Sopenharmony_ci const void *buf, 2368c2ecf20Sopenharmony_ci size_t len) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci if (level <= event_log_level) { 2398c2ecf20Sopenharmony_ci print_hex_dump(translate_esas2r_event_level_to_kernel(level), 2408c2ecf20Sopenharmony_ci "", DUMP_PREFIX_OFFSET, 16, 1, buf, 2418c2ecf20Sopenharmony_ci len, true); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 1; 2458c2ecf20Sopenharmony_ci} 246