/*- * BSD LICENSE * * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. * Copyright(c) 2012-2014 6WIND S.A. All rights reserved. * Copyright (c) 2017, Western Digital Corporation or its affiliates. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "nvme_pci.h" #include "nvme_common.h" #include "nvme_mem.h" #ifndef __HAIKU__ #include "nvme_cpu.h" #endif #include #include #include #if defined(NVME_ARCH_X86) #include #endif #include #include #ifndef __HAIKU__ #include #include #endif /* * Trim whitespace from a string in place. */ void nvme_str_trim(char *s) { char *p, *q; /* Remove header */ p = s; while (*p != '\0' && isspace(*p)) p++; /* Remove tailer */ q = p + strlen(p); while (q - 1 >= p && isspace(*(q - 1))) { q--; *q = '\0'; } /* if remove header, move */ if (p != s) { q = s; while (*p != '\0') *q++ = *p++; *q = '\0'; } } /* * Split string into tokens */ int nvme_str_split(char *string, int stringlen, char **tokens, int maxtokens, char delim) { int i, tok = 0; int tokstart = 1; if (string == NULL || tokens == NULL) { errno = EINVAL; return -1; } for (i = 0; i < stringlen; i++) { if (string[i] == '\0' || tok >= maxtokens) break; if (tokstart) { tokstart = 0; tokens[tok++] = &string[i]; } if (string[i] == delim) { string[i] = '\0'; tokstart = 1; } } return tok; } #ifndef __HAIKU__ /* * Parse a sysfs (or other) file containing one integer value */ int nvme_parse_sysfs_value(const char *filename, unsigned long *val) { FILE *f; char buf[BUFSIZ]; char *end = NULL; if ((f = fopen(filename, "r")) == NULL) { nvme_err("%s(): cannot open sysfs value %s\n", __func__, filename); return -1; } if (fgets(buf, sizeof(buf), f) == NULL) { nvme_err("%s(): cannot read sysfs value %s\n", __func__, filename); fclose(f); return -1; } *val = strtoul(buf, &end, 0); if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { nvme_err("%s(): cannot parse sysfs value %s\n", __func__, filename); fclose(f); return -1; } fclose(f); return 0; } /* * Get a block device block size in Bytes. */ ssize_t nvme_dev_get_blocklen(int fd) { uint32_t blocklen = 0; if (ioctl(fd, BLKSSZGET, &blocklen) < 0) { nvme_err("iioctl BLKSSZGET failed %d (%s)\n", errno, strerror(errno)); return -1; } return blocklen; } #endif /* * Get a file size in Bytes. */ uint64_t nvme_file_get_size(int fd) { struct stat st; if (fstat(fd, &st) != 0) return 0; if (S_ISLNK(st.st_mode)) return 0; if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { #ifndef __HAIKU__ uint64_t size; if (ioctl(fd, BLKGETSIZE64, &size) == 0) return size; else #endif return 0; } if (S_ISREG(st.st_mode)) return st.st_size; /* Not REG, CHR or BLK */ return 0; } #ifndef __HAIKU__ /* * Dump the stack of the calling core. */ static void nvme_dump_stack(void) { #define BACKTRACE_SIZE 256 void *func[BACKTRACE_SIZE]; char **symb = NULL; int size; size = backtrace(func, BACKTRACE_SIZE); symb = backtrace_symbols(func, size); if (symb == NULL) return; while (size > 0) { nvme_crit("%d: [%s]\n", size, symb[size - 1]); size --; } free(symb); } #endif #ifndef __HAIKU__ void /* * call abort(), it will generate a coredump if enabled. */ void __nvme_panic(const char *funcname, const char *format, ...) { va_list ap; nvme_crit("PANIC in %s():\n", funcname); va_start(ap, format); nvme_vlog(NVME_LOG_CRIT, format, ap); va_end(ap); nvme_dump_stack(); abort(); } #endif /** * Library initialization: must be run first by any application * before calling any libnvme API. */ int nvme_lib_init(enum nvme_log_level level, enum nvme_log_facility facility, const char *path) { int ret; #ifndef __HAIKU__ /* Set log level and facility first */ nvme_set_log_level(level); nvme_set_log_facility(facility, path); /* Gather CPU information */ ret = nvme_cpu_init(); if (ret != 0) { nvme_crit("Failed to gather CPU information\n"); goto out; } #endif /* PCI subsystem initialization (libpciaccess) */ ret = nvme_pci_init(); if (ret != 0) { nvme_crit("PCI subsystem initialization failed\n"); goto out; } /* Initialize memory management */ ret = nvme_mem_init(); if (ret != 0) nvme_crit("Memory management initialization failed\n"); out: return ret; } /* * Will be executed automatically last on termination of the user application. */ __attribute__((destructor)) void nvme_lib_exit(void) { nvme_ctrlr_cleanup(); nvme_mem_cleanup(); }