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 */
93 extern void nvme_str_trim(char *s);
94
95 /*
96 * Split string into tokens
97 */
98 extern 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 */
nvme_str2size(const char * str)110 static 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 */
151 extern int nvme_parse_sysfs_value(const char *filename, unsigned long *val);
152
153 /*
154 * Get a file size in Bytes.
155 */
156 extern uint64_t nvme_file_get_size(int fd);
157
158 /*
159 * Get a block device block size in Bytes.
160 */
161 extern ssize_t nvme_dev_get_blocklen(int fd);
162
163 /*
164 * Get current time in nano seconds.
165 */
nvme_time_nsec(void)166 static 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 */
nvme_time_usec(void)183 static 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 */
nvme_time_msec(void)191 static 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>
nvme_pause(void)201 static inline void nvme_pause(void)
202 {
203 _mm_pause();
204 }
205 #else
nvme_pause(void)206 static inline void nvme_pause(void) {}
207 #endif
208
209 #ifdef __HAIKU__
210 static inline void
nvme_usleep(int usecs)211 nvme_usleep(int usecs)
212 {
213 snooze(usecs);
214 }
215
216 static inline void
nvme_msleep(int msecs)217 nvme_msleep(int msecs)
218 {
219 snooze(msecs * 1000LL);
220 }
221 #else
222 /*
223 * Micro-seconds sleep.
224 */
nvme_usleep(int usecs)225 static 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 */
nvme_msleep(int msecs)237 static 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 */
252 extern 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 */
nvme_is_pow2(__u64 v)317 static 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 */
nvme_align_pow2(__u64 v)325 static 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 */
nvme_log2(size_t size)341 static 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 */
test_bit(__u8 * bitmap,unsigned int bit)365 static 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 */
set_bit(__u8 * bitmap,unsigned int bit)373 static 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 */
clear_bit(__u8 * bitmap,unsigned int bit)381 static 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 */
find_first_zero_bit(__u8 * bitmap,unsigned int nr_bits)390 static 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 */
413 extern void nvme_ctrlr_cleanup(void);
414
415 #endif /* __NVME_COMMON_H__ */
416