xref: /haiku/src/add-ons/kernel/drivers/disk/nvme/libnvme/nvme_common.c (revision 5b189b0e1e2f51f367bfcb126b2f00a3702f352d)
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