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