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 */
59void 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 */
87int 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 */
118int 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 */
151ssize_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 */
169uint64_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 */
200static 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__
223void
224/*
225 * call abort(), it will generate a coredump if enabled.
226 */
227void __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 */
244int 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
274out:
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