1/*- 2 * Copyright (C) 2009-2012 Semihalf 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/malloc.h> 35#include <sys/proc.h> 36#include <sys/alq.h> 37#include <sys/time.h> 38 39#include <machine/stdarg.h> 40 41#include <dev/nand/nandsim_log.h> 42 43int nandsim_log_level; 44int nandsim_log_output; 45int log_size = NANDSIM_RAM_LOG_SIZE; 46 47static int nandsim_entry_size = NANDSIM_ENTRY_SIZE; 48static int nandsim_entry_count = NANDSIM_ENTRY_COUNT; 49static int str_index = 0; 50static char string[NANDSIM_ENTRY_SIZE + 1] = {0}; 51 52int 53nandsim_log_init(struct nandsim_softc *sc, char *filename) 54{ 55 int error = 0; 56 57 if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { 58 error = alq_open(&sc->alq, filename, 59 curthread->td_ucred, 0644, 60 nandsim_entry_size, nandsim_entry_count); 61 } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { 62 sc->log_buff = malloc(log_size, M_NANDSIM, M_WAITOK | M_ZERO); 63 if (!sc->log_buff) 64 error = ENOMEM; 65 } 66 67 return (error); 68} 69 70void 71nandsim_log_close(struct nandsim_softc *sc) 72{ 73 74 if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { 75 memset(&string[str_index], 0, NANDSIM_ENTRY_SIZE - str_index); 76 alq_write(sc->alq, (void *) string, ALQ_NOWAIT); 77 str_index = 0; 78 string[0] = '\0'; 79 alq_close(sc->alq); 80 } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { 81 free(sc->log_buff, M_NANDSIM); 82 sc->log_buff = NULL; 83 } 84} 85 86void 87nandsim_log(struct nandsim_chip *chip, int level, const char *fmt, ...) 88{ 89 char hdr[TIME_STR_SIZE]; 90 char tmp[NANDSIM_ENTRY_SIZE]; 91 struct nandsim_softc *sc; 92 struct timeval currtime; 93 va_list ap; 94 int hdr_len, len, rest; 95 96 if (nandsim_log_output == NANDSIM_OUTPUT_NONE) 97 return; 98 99 if (chip == NULL) 100 return; 101 102 sc = chip->sc; 103 if (!sc->alq && nandsim_log_output == NANDSIM_OUTPUT_FILE) 104 return; 105 106 if (level <= nandsim_log_level) { 107 microtime(&currtime); 108 hdr_len = sprintf(hdr, "%08jd.%08li [chip:%d, ctrl:%d]: ", 109 (intmax_t)currtime.tv_sec, currtime.tv_usec, 110 chip->chip_num, chip->ctrl_num); 111 112 switch(nandsim_log_output) { 113 case NANDSIM_OUTPUT_CONSOLE: 114 printf("%s", hdr); 115 va_start(ap, fmt); 116 vprintf(fmt, ap); 117 va_end(ap); 118 break; 119 case NANDSIM_OUTPUT_RAM: 120 va_start(ap, fmt); 121 len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); 122 tmp[NANDSIM_ENTRY_SIZE - 1] = 0; 123 va_end(ap); 124 125 rest = log_size - sc->log_idx - 1; 126 if (rest >= hdr_len) { 127 bcopy(hdr, &sc->log_buff[sc->log_idx], 128 hdr_len); 129 sc->log_idx += hdr_len; 130 sc->log_buff[sc->log_idx] = 0; 131 } else { 132 bcopy(hdr, &sc->log_buff[sc->log_idx], rest); 133 bcopy(&hdr[rest], sc->log_buff, 134 hdr_len - rest); 135 sc->log_idx = hdr_len - rest; 136 sc->log_buff[sc->log_idx] = 0; 137 } 138 139 rest = log_size - sc->log_idx - 1; 140 if (rest >= len) { 141 bcopy(tmp, &sc->log_buff[sc->log_idx], len); 142 sc->log_idx += len; 143 sc->log_buff[sc->log_idx] = 0; 144 } else { 145 bcopy(tmp, &sc->log_buff[sc->log_idx], rest); 146 bcopy(&tmp[rest], sc->log_buff, len - rest); 147 sc->log_idx = len - rest; 148 sc->log_buff[sc->log_idx] = 0; 149 } 150 151 break; 152 153 case NANDSIM_OUTPUT_FILE: 154 va_start(ap, fmt); 155 len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); 156 tmp[NANDSIM_ENTRY_SIZE - 1] = 0; 157 va_end(ap); 158 159 rest = NANDSIM_ENTRY_SIZE - str_index; 160 if (rest >= hdr_len) { 161 strcat(string, hdr); 162 str_index += hdr_len; 163 } else { 164 strlcat(string, hdr, NANDSIM_ENTRY_SIZE + 1); 165 alq_write(sc->alq, (void *) string, 166 ALQ_NOWAIT); 167 strcpy(string, &hdr[rest]); 168 str_index = hdr_len - rest; 169 } 170 rest = NANDSIM_ENTRY_SIZE - str_index; 171 if (rest >= len) { 172 strcat(string, tmp); 173 str_index += len; 174 } else { 175 strlcat(string, tmp, NANDSIM_ENTRY_SIZE + 1); 176 alq_write(sc->alq, (void *) string, 177 ALQ_NOWAIT); 178 strcpy(string, &tmp[rest]); 179 str_index = len - rest; 180 } 181 break; 182 default: 183 break; 184 } 185 } 186} 187