1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. 5 * Copyright(c) 2012-2014 6WIND S.A. All rights reserved. 6 * Copyright (c) 2017, Western Digital Corporation or its affiliates. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "nvme_pci.h" 36 #include "nvme_common.h" 37 #include "nvme_mem.h" 38 #ifndef __HAIKU__ 39 #include "nvme_cpu.h" 40 #endif 41 42 #include <fcntl.h> 43 #include <sys/file.h> 44 #include <sys/stat.h> 45 46 #if defined(NVME_ARCH_X86) 47 #include <sys/io.h> 48 #endif 49 #include <sys/ioctl.h> 50 #include <sys/types.h> 51 #ifndef __HAIKU__ 52 #include <linux/fs.h> 53 #include <execinfo.h> 54 #endif 55 56 /* 57 * Trim whitespace from a string in place. 58 */ 59 void nvme_str_trim(char *s) 60 { 61 char *p, *q; 62 63 /* Remove header */ 64 p = s; 65 while (*p != '\0' && isspace(*p)) 66 p++; 67 68 /* Remove tailer */ 69 q = p + strlen(p); 70 while (q - 1 >= p && isspace(*(q - 1))) { 71 q--; 72 *q = '\0'; 73 } 74 75 /* if remove header, move */ 76 if (p != s) { 77 q = s; 78 while (*p != '\0') 79 *q++ = *p++; 80 *q = '\0'; 81 } 82 } 83 84 /* 85 * Split string into tokens 86 */ 87 int nvme_str_split(char *string, int stringlen, 88 char **tokens, int maxtokens, char delim) 89 { 90 int i, tok = 0; 91 int tokstart = 1; 92 93 if (string == NULL || tokens == NULL) { 94 errno = EINVAL; 95 return -1; 96 } 97 98 for (i = 0; i < stringlen; i++) { 99 if (string[i] == '\0' || tok >= maxtokens) 100 break; 101 if (tokstart) { 102 tokstart = 0; 103 tokens[tok++] = &string[i]; 104 } 105 if (string[i] == delim) { 106 string[i] = '\0'; 107 tokstart = 1; 108 } 109 } 110 111 return tok; 112 } 113 114 #ifndef __HAIKU__ 115 /* 116 * Parse a sysfs (or other) file containing one integer value 117 */ 118 int nvme_parse_sysfs_value(const char *filename, 119 unsigned long *val) 120 { 121 FILE *f; 122 char buf[BUFSIZ]; 123 char *end = NULL; 124 125 if ((f = fopen(filename, "r")) == NULL) { 126 nvme_err("%s(): cannot open sysfs value %s\n", 127 __func__, filename); 128 return -1; 129 } 130 131 if (fgets(buf, sizeof(buf), f) == NULL) { 132 nvme_err("%s(): cannot read sysfs value %s\n", 133 __func__, filename); 134 fclose(f); 135 return -1; 136 } 137 *val = strtoul(buf, &end, 0); 138 if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { 139 nvme_err("%s(): cannot parse sysfs value %s\n", 140 __func__, filename); 141 fclose(f); 142 return -1; 143 } 144 fclose(f); 145 return 0; 146 } 147 148 /* 149 * Get a block device block size in Bytes. 150 */ 151 ssize_t nvme_dev_get_blocklen(int fd) 152 { 153 uint32_t blocklen = 0; 154 155 if (ioctl(fd, BLKSSZGET, &blocklen) < 0) { 156 nvme_err("iioctl BLKSSZGET failed %d (%s)\n", 157 errno, 158 strerror(errno)); 159 return -1; 160 } 161 162 return blocklen; 163 } 164 #endif 165 166 /* 167 * Get a file size in Bytes. 168 */ 169 uint64_t nvme_file_get_size(int fd) 170 { 171 struct stat st; 172 173 if (fstat(fd, &st) != 0) 174 return 0; 175 176 if (S_ISLNK(st.st_mode)) 177 return 0; 178 179 if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { 180 #ifndef __HAIKU__ 181 uint64_t size; 182 if (ioctl(fd, BLKGETSIZE64, &size) == 0) 183 return size; 184 else 185 #endif 186 return 0; 187 } 188 189 if (S_ISREG(st.st_mode)) 190 return st.st_size; 191 192 /* Not REG, CHR or BLK */ 193 return 0; 194 } 195 196 #ifndef __HAIKU__ 197 /* 198 * Dump the stack of the calling core. 199 */ 200 static void nvme_dump_stack(void) 201 { 202 #define BACKTRACE_SIZE 256 203 void *func[BACKTRACE_SIZE]; 204 char **symb = NULL; 205 int size; 206 207 size = backtrace(func, BACKTRACE_SIZE); 208 symb = backtrace_symbols(func, size); 209 210 if (symb == NULL) 211 return; 212 213 while (size > 0) { 214 nvme_crit("%d: [%s]\n", size, symb[size - 1]); 215 size --; 216 } 217 218 free(symb); 219 } 220 #endif 221 222 #ifndef __HAIKU__ 223 void 224 /* 225 * call abort(), it will generate a coredump if enabled. 226 */ 227 void __nvme_panic(const char *funcname, const char *format, ...) 228 { 229 va_list ap; 230 231 nvme_crit("PANIC in %s():\n", funcname); 232 va_start(ap, format); 233 nvme_vlog(NVME_LOG_CRIT, format, ap); 234 va_end(ap); 235 nvme_dump_stack(); 236 abort(); 237 } 238 #endif 239 240 /** 241 * Library initialization: must be run first by any application 242 * before calling any libnvme API. 243 */ 244 int nvme_lib_init(enum nvme_log_level level, 245 enum nvme_log_facility facility, const char *path) 246 { 247 int ret; 248 249 #ifndef __HAIKU__ 250 /* Set log level and facility first */ 251 nvme_set_log_level(level); 252 nvme_set_log_facility(facility, path); 253 254 /* Gather CPU information */ 255 ret = nvme_cpu_init(); 256 if (ret != 0) { 257 nvme_crit("Failed to gather CPU information\n"); 258 goto out; 259 } 260 #endif 261 262 /* PCI subsystem initialization (libpciaccess) */ 263 ret = nvme_pci_init(); 264 if (ret != 0) { 265 nvme_crit("PCI subsystem initialization failed\n"); 266 goto out; 267 } 268 269 /* Initialize memory management */ 270 ret = nvme_mem_init(); 271 if (ret != 0) 272 nvme_crit("Memory management initialization failed\n"); 273 274 out: 275 276 return ret; 277 } 278 279 /* 280 * Will be executed automatically last on termination of the user application. 281 */ 282 __attribute__((destructor)) void nvme_lib_exit(void) 283 { 284 285 nvme_ctrlr_cleanup(); 286 287 nvme_mem_cleanup(); 288 289 } 290