1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5 *   Copyright (c) 2017, Western Digital Corporation or its affiliates.
6 *
7 *   Redistribution and use in source and binary forms, with or without
8 *   modification, are permitted provided that the following conditions
9 *   are met:
10 *
11 *     * Redistributions of source code must retain the above copyright
12 *       notice, this list of conditions and the following disclaimer.
13 *     * Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *     * Neither the name of Intel Corporation nor the names of its
18 *       contributors may be used to endorse or promote products derived
19 *       from this software without specific prior written permission.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef __NVME_COMMON_H__
35#define __NVME_COMMON_H__
36
37#define _GNU_SOURCE
38#define _FILE_OFFSET_BITS 64
39
40#include <stdlib.h>
41#include <stdio.h>
42#include <stdint.h>
43#include <stddef.h>
44#include <stdbool.h>
45#include <stdarg.h>
46#include <string.h>
47#include <ctype.h>
48#include <errno.h>
49#include <inttypes.h>
50#include <unistd.h>
51#include <limits.h>
52#include <time.h>
53#include <sys/types.h>
54#include <sys/cdefs.h>
55#include <sys/queue.h>
56#ifndef __HAIKU__
57#include <linux/types.h>
58#endif
59
60#include "libnvme/nvme.h"
61#include "nvme_arch.h"
62#include "nvme_log.h"
63
64/*
65 * Check if a branch is likely to be taken.
66 */
67#ifndef likely
68#if __GNUC__ < 3
69#define likely(x) x
70#else
71#define likely(x)  __builtin_expect((x),1)
72#endif
73#endif /* likely */
74
75/*
76 * Check if a branch is unlikely to be taken.
77 */
78#ifndef unlikely
79#if __GNUC__ < 3
80#define unlikely(x) x
81#else
82#define unlikely(x)  __builtin_expect((x),0)
83#endif
84#endif /* unlikely */
85
86#ifndef typeof
87#define typeof __typeof__
88#endif
89
90/*
91 * Trim whitespace from a string in place.
92 */
93extern void nvme_str_trim(char *s);
94
95/*
96 * Split string into tokens
97 */
98extern int nvme_str_split(char *string, int stringlen,
99			  char **tokens, int maxtokens, char delim);
100
101/*
102 * Converts a numeric string to the equivalent uint64_t value.
103 * As well as straight number conversion, also recognises the suffixes
104 * k, m and g for kilobytes, megabytes and gigabytes respectively.
105 *
106 * If a negative number is passed in, zero is returned.
107 * Zero is also returned in the case of an error with the
108 * strtoull call in the function.
109 */
110static inline size_t nvme_str2size(const char *str)
111{
112	unsigned long long size;
113	char *endptr;
114
115	while (isspace((int)*str))
116		str++;
117	if (*str == '-')
118		return 0;
119
120	errno = 0;
121	size = strtoull(str, &endptr, 0);
122	if (errno)
123		return 0;
124
125	/* Allow 1 space gap between number and unit */
126	if (*endptr == ' ')
127		endptr++;
128
129	switch (*endptr){
130	case 'G':
131	case 'g':
132		size *= 1024;
133		/* Fall through */
134	case 'M':
135	case 'm':
136		/* Fall through */
137		size *= 1024;
138	case 'K':
139	case 'k':
140		/* Fall through */
141		size *= 1024;
142	}
143
144	return size;
145}
146
147/*
148 * Function to read a single numeric value from a file on the filesystem.
149 * Used to read information from files on /sys
150 */
151extern int nvme_parse_sysfs_value(const char *filename, unsigned long *val);
152
153/*
154 * Get a file size in Bytes.
155 */
156extern uint64_t nvme_file_get_size(int fd);
157
158/*
159 * Get a block device block size in Bytes.
160 */
161extern ssize_t nvme_dev_get_blocklen(int fd);
162
163/*
164 * Get current time in nano seconds.
165 */
166static inline unsigned long long nvme_time_nsec(void)
167{
168#ifdef __HAIKU__
169	return (unsigned long long)system_time();
170#else
171	struct timespec ts;
172
173	clock_gettime(CLOCK_REALTIME, &ts);
174
175	return (unsigned long long) ts.tv_sec * 1000000000ULL
176		+ (unsigned long long) ts.tv_nsec;
177#endif
178}
179
180/*
181 * Get current time in micro seconds.
182 */
183static inline unsigned long long nvme_time_usec(void)
184{
185	return nvme_time_nsec() / 1000;
186}
187
188/*
189 * Get current time in milli seconds.
190 */
191static inline unsigned long long nvme_time_msec(void)
192{
193	return nvme_time_nsec() / 1000000;
194}
195
196/*
197 * PAUSE instruction for tight loops (avoid busy waiting)
198 */
199#ifdef __SSE2__
200#include <emmintrin.h>
201static inline void nvme_pause(void)
202{
203	_mm_pause();
204}
205#else
206static inline void nvme_pause(void) {}
207#endif
208
209#ifdef __HAIKU__
210static inline void
211nvme_usleep(int usecs)
212{
213	snooze(usecs);
214}
215
216static inline void
217nvme_msleep(int msecs)
218{
219	snooze(msecs * 1000LL);
220}
221#else
222/*
223 * Micro-seconds sleep.
224 */
225static inline void nvme_usleep(int usecs)
226{
227	struct timeval tv;
228
229	tv.tv_sec = usecs / 1000000;
230	tv.tv_usec = usecs % 1000000;
231	select(0, NULL, NULL, NULL, &tv);
232}
233
234/*
235 * Milli-seconds sleep.
236 */
237static inline void nvme_msleep(int msecs)
238{
239	struct timeval tv;
240
241	tv.tv_sec = msecs / 1000;
242	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
243	select(0, NULL, NULL, NULL, &tv);
244}
245#endif
246
247#ifndef __HAIKU__
248/*
249 * Provide notification of a critical non-recoverable error and stop.
250 * This function should not be called directly. Use nvme_panic() instead.
251 */
252extern void __nvme_panic(const char *funcname , const char *format, ...)
253#ifdef __GNUC__
254#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2))
255	__attribute__((cold))
256#endif
257#endif
258	__attribute__((noreturn))
259	__attribute__((format(printf, 2, 3)));
260
261/*
262 * Provide notification of a critical non-recoverable error
263 * and terminate execution abnormally.
264 */
265#define nvme_panic(format, args...)	\
266	__nvme_panic(__FUNCTION__, format, ## args)
267#else
268#define nvme_panic panic
269#endif
270
271/*
272 * Macro to evaluate a scalar expression and
273 * abort the program if the assertion is false.
274 */
275#define _nvme_assert_default(exp)					\
276	do {								\
277		if (unlikely(!(exp)))					\
278			nvme_panic("line %d, assert %s failed\n",	\
279				   __LINE__, # exp);			\
280	} while (0)
281
282#define _nvme_assert_msg(exp, msg)					\
283	do {								\
284		if (unlikely(!(exp)))					\
285			nvme_panic("%s\n", msg);			\
286	} while (0)
287
288#define _NVME_GET_ASSERT_OVERLOAD(_1, _2, NAME, args...) NAME
289
290#define nvme_assert(args...) \
291	_NVME_GET_ASSERT_OVERLOAD(args,					\
292				  _nvme_assert_msg,			\
293				  _nvme_assert_default)			\
294				  (args)
295
296/*
297 * Macro to return the minimum of two numbers
298 */
299#define nvme_min(a, b) ({	     \
300		typeof (a) _a = (a); \
301		typeof (b) _b = (b); \
302		_a < _b ? _a : _b;   \
303	})
304
305/*
306 * Macro to return the maximum of two numbers
307 */
308#define nvme_max(a, b) ({	     \
309		typeof (a) _a = (a); \
310		typeof (b) _b = (b); \
311		_a > _b ? _a : _b;   \
312	})
313
314/*
315 * Returns true if n is a power of 2.
316 */
317static inline int nvme_is_pow2(__u64 v)
318{
319	return v && !(v & (v - 1));
320}
321
322/*
323 * Return the power of 2 immediately after v.
324 */
325static inline __u64 nvme_align_pow2(__u64 v)
326{
327	v--;
328	v |= v >> 1;
329	v |= v >> 2;
330	v |= v >> 4;
331	v |= v >> 8;
332	v |= v >> 16;
333	v |= v >> 32;
334
335	return v + 1;
336}
337
338/*
339 * Calculate log2 of a power of 2 size.
340 */
341static inline size_t nvme_log2(size_t size)
342{
343	size_t bits = 0;
344
345        if (!nvme_is_pow2(size))
346                return 0;
347
348        while (size >>= 1)
349		bits++;
350
351	return bits;
352}
353
354/*
355 * Handle alignements.
356 */
357#define nvme_align_down(val, align)	\
358	((val) & (~((typeof(val))((align) - 1))))
359#define nvme_align_up(val, align)	\
360	nvme_align_down((val) + (align) - 1, (align))
361
362/*
363 * Test a bit value.
364 */
365static inline int test_bit(__u8 *bitmap, unsigned int bit)
366{
367        return bitmap[bit >> 3] & (1U << (bit & 0x7));
368}
369
370/*
371 * Set a bit.
372 */
373static inline void set_bit(__u8 *bitmap, unsigned int bit)
374{
375        bitmap[bit >> 3] |= 1U << (bit & 0x7);
376}
377
378/*
379 * Clear a bit.
380 */
381static inline void clear_bit(__u8 *bitmap, unsigned int bit)
382{
383        bitmap[bit >> 3] &= ~(1U << (bit & 0x7));
384}
385
386/*
387 * Find the first zero bit in a bitmap of size nr_bits.
388 * If no zero bit is found, return -1.
389 */
390static inline int find_first_zero_bit(__u8 *bitmap, unsigned int nr_bits)
391{
392	__u64 *b = (__u64 *)bitmap;
393	unsigned int i, j, bit, count = (nr_bits + 63) >> 6;
394
395	for(i = 0; i < count; i++) {
396		if (b[i] != ~0UL)
397			break;
398	}
399
400	bit = i << 6;
401	for (j = bit; j < nr_bits; j++) {
402		if (!test_bit(bitmap, j))
403			return j;
404	}
405
406	return -1;
407}
408
409/*
410 * Close all open controllers on exit.
411 * Defined in lib/nvme/nvme.c
412 */
413extern void nvme_ctrlr_cleanup(void);
414
415#endif /* __NVME_COMMON_H__ */
416