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 */
nvme_str_trim(char * s)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 */
nvme_str_split(char * string,int stringlen,char ** tokens,int maxtokens,char delim)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 */
nvme_parse_sysfs_value(const char * filename,unsigned long * val)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 */
nvme_dev_get_blocklen(int fd)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 */
nvme_file_get_size(int fd)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 */
nvme_dump_stack(void)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 */
__nvme_panic(const char * funcname,const char * format,...)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 */
nvme_lib_init(enum nvme_log_level level,enum nvme_log_facility facility,const char * path)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 */
nvme_lib_exit(void)282 __attribute__((destructor)) void nvme_lib_exit(void)
283 {
284
285 nvme_ctrlr_cleanup();
286
287 nvme_mem_cleanup();
288
289 }
290