xref: /freebsd/sys/dev/ocs_fc/ocs_os.h (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1 /*-
2  * Copyright (c) 2017 Broadcom. All rights reserved.
3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 /**
35  * @file
36  * bsd specific headers common to the driver
37  */
38 
39 #ifndef _OCS_OS_H
40 #define _OCS_OS_H
41 
42 /***************************************************************************
43  * OS specific includes
44  */
45 #include "opt_stack.h"
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/malloc.h>
50 #include <sys/kernel.h>
51 #include <sys/module.h>
52 #include <sys/bus.h>
53 #include <sys/rman.h>
54 #include <sys/endian.h>
55 #include <sys/stddef.h>
56 #include <sys/lock.h>
57 #include <sys/mutex.h>
58 #include <sys/taskqueue.h>
59 #include <sys/bitstring.h>
60 #include <sys/stack.h>
61 
62 #include <machine/atomic.h>
63 #include <machine/bus.h>
64 #include <machine/stdarg.h>
65 
66 #include <dev/pci/pcivar.h>
67 
68 #include <sys/sema.h>
69 #include <sys/time.h>
70 
71 #include <sys/proc.h>
72 #include <sys/kthread.h>
73 #include <sys/unistd.h>
74 #include <sys/sched.h>
75 
76 #include <sys/conf.h>
77 #include <sys/sysctl.h>
78 #include <sys/ioccom.h>
79 #include <sys/ctype.h>
80 
81 #include <sys/linker.h>		/* for debug of memory allocations */
82 
83 /* OCS_OS_MAX_ISR_TIME_MSEC -  maximum time driver code should spend in an interrupt
84  * or kernel thread context without yielding
85  */
86 #define OCS_OS_MAX_ISR_TIME_MSEC	1000
87 
88 /* BSD driver specific definitions */
89 
90 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
91 
92 #define OCS_MAX_LUN			512
93 #define OCS_NUM_UNSOLICITED_FRAMES	1024
94 
95 #define OCS_MAX_DOMAINS			1
96 #define OCS_MAX_REMOTE_NODES		2048
97 #define OCS_MAX_TARGETS			1024
98 #define OCS_MAX_INITIATORS		1024
99 /** Reserve this number of IO for each intiator to return FULL/BUSY status */
100 #define OCS_RSVD_INI_IO			8
101 
102 #define OCS_MIN_DMA_ALIGNMENT		16
103 #define OCS_MAX_DMA_ALLOC		(64*1024)	/* maxium DMA allocation that is expected to reliably succeed  */
104 
105 /*
106  * Macros used to size the CQ hash table. We want to round up to the next
107  * power of 2 for the hash.
108  */
109 #define B2(x)   (   (x) | (   (x) >> 1) )
110 #define B4(x)   ( B2(x) | ( B2(x) >> 2) )
111 #define B8(x)   ( B4(x) | ( B4(x) >> 4) )
112 #define B16(x)  ( B8(x) | ( B8(x) >> 8) )
113 #define B32(x)  (B16(x) | (B16(x) >>16) )
114 #define B32_NEXT_POWER_OF_2(x)      (B32((x)-1) + 1)
115 
116 /*
117  * likely/unlikely - branch prediction hint
118  */
119 #define likely(x)               __builtin_expect(!!(x), 1)
120 #define unlikely(x)             __builtin_expect(!!(x), 0)
121 
122 /***************************************************************************
123  * OS abstraction
124  */
125 
126 /**
127  * @brief Min/Max macros
128  *
129  */
130 #define OCS_MAX(x, y)		((x) > (y) ? (x) : (y))
131 #define OCS_MIN(x, y)		((x) < (y) ? (x) : (y))
132 
133 #define PRIX64	"lX"
134 #define PRIx64	"lx"
135 #define PRId64	"ld"
136 #define PRIu64	"lu"
137 
138 /**
139  * Enable optional features
140  *  - OCS_INCLUDE_DEBUG include low-level SLI debug support
141  */
142 #define OCS_INCLUDE_DEBUG
143 
144 /**
145  * @brief Set the Nth bit
146  *
147  * @todo move to a private file used internally?
148  */
149 #ifndef BIT
150 #define BIT(n)		(1U << (n))
151 #endif
152 
153 /***************************************************************************
154  * Platform specific operations
155  */
156 
157 typedef struct ocs_softc ocs_t;
158 
159 /**
160  * @ingroup os
161  * @typedef ocs_os_handle_t
162  * @brief OS specific handle or driver context
163  *
164  * This can be anything from a void * to some other OS specific type. The lower
165  * layers make no assumption about its value and pass it back as the first
166  * parameter to most OS functions.
167  */
168 typedef ocs_t * ocs_os_handle_t;
169 
170 /**
171  * @ingroup os
172  * @brief return the lower 32-bits of a bus address
173  *
174  * @param addr Physical or bus address to convert
175  * @return lower 32-bits of a bus address
176  *
177  * @note this may be a good cadidate for an inline or macro
178  */
179 static inline uint32_t ocs_addr32_lo(uintptr_t addr)
180 {
181 #if defined(__LP64__)
182 	return (uint32_t)(addr & 0xffffffffUL);
183 #else
184 	return addr;
185 #endif
186 }
187 
188 /**
189  * @ingroup os
190  * @brief return the upper 32-bits of a bus address
191  *
192  * @param addr Physical or bus address to convert
193  * @return upper 32-bits of a bus address
194  *
195  * @note this may be a good cadidate for an inline or macro
196  */
197 static inline uint32_t ocs_addr32_hi(uintptr_t addr)
198 {
199 #if defined(__LP64__)
200 	return (uint32_t)(addr >> 32);
201 #else
202 	return 0;
203 #endif
204 }
205 
206 /**
207  * @ingroup os
208  * @brief return the log2(val)
209  *
210  * @param val number to use (assumed to be exact power of 2)
211  *
212  * @return log base 2 of val
213  */
214 static inline uint32_t ocs_lg2(uint32_t val)
215 {
216 #if defined(__GNUC__)
217 	/*
218 	 * clz = "count leading zero's"
219 	 *
220 	 * Assuming val is an exact power of 2, the most significant bit
221 	 * will be the log base 2 of val
222 	 */
223 	return 31 - __builtin_clz(val);
224 #else
225 #error You need to provide a non-GCC version of this function
226 #endif
227 }
228 
229 /**
230  * @ingroup os
231  * @brief optimization barrier
232  *
233  * Optimization barrier. Prevents compiler re-ordering
234  * instructions across barrier.
235  *
236  * @return none
237  */
238 #define ocs_barrier()	 __asm __volatile("" : : : "memory");
239 
240 /**
241  * @ingroup os
242  * @brief convert a big endian 32 bit value to the host's native format
243  *
244  * @param val 32 bit big endian value
245  *
246  * @return value converted to the host's native endianness
247  */
248 #define ocs_be32toh(val)	be32toh(val)
249 
250 /**
251  * @ingroup os
252  * @brief convert a 32 bit value from the host's native format to big endian
253  *
254  * @param val 32 bit native endian value
255  *
256  * @return value converted to big endian
257  */
258 #define ocs_htobe32(val)	htobe32(val)
259 
260 /**
261  * @ingroup os
262  * @brief convert a 16 bit value from the host's native format to big endian
263  *
264  * @param v 16 bit native endian value
265  *
266  * @return value converted to big endian
267  */
268 #define ocs_htobe16(v)	htobe16(v)
269 #define ocs_be16toh(v)	be16toh(v)
270 
271 
272 #define ocs_htobe64(v)	htobe64(v)
273 #define ocs_be64toh(v)	be64toh(v)
274 
275 /**
276  * @ingroup os
277  * @brief Delay execution by the given number of micro-seconds
278  *
279  * @param usec number of micro-seconds to "busy-wait"
280  *
281  * @note The value of usec may be greater than 1,000,000
282  */
283 #define ocs_udelay(usec) DELAY(usec)
284 
285 /**
286  * @ingroup os
287  * @brief Delay execution by the given number of milli-seconds
288  *
289  * @param msec number of milli-seconds to "busy-wait"
290  *
291  * @note The value of usec may be greater than 1,000,000
292  */
293 #define ocs_msleep(msec) ocs_udelay((msec)*1000)
294 
295 /**
296  * @ingroup os
297  * @brief Get time of day in msec
298  *
299  * @return time of day in msec
300  */
301 static inline time_t
302 ocs_msectime(void)
303 {
304 	struct timeval tv;
305 
306 	getmicrotime(&tv);
307 	return (tv.tv_sec*1000) + (tv.tv_usec / 1000);
308 }
309 
310 /**
311  * @ingroup os
312  * @brief Copy length number of bytes from the source to destination address
313  *
314  * @param d pointer to the destination memory
315  * @param s pointer to the source memory
316  * @param l number of bytes to copy
317  *
318  * @return original value of dst pointer
319  */
320 #define ocs_memcpy(d, s, l)		memcpy(d, s, l)
321 
322 #define ocs_strlen(s)			strlen(s)
323 #define ocs_strcpy(d,s)			strcpy(d, s)
324 #define ocs_strncpy(d,s, n)		strncpy(d, s, n)
325 #define ocs_strcat(d, s)		strcat(d, s)
326 #define ocs_strtoul(s,ep,b)		strtoul(s,ep,b)
327 #define ocs_strtoull(s,ep,b)		((uint64_t)strtouq(s,ep,b))
328 #define ocs_atoi(s)			strtol(s, 0, 0)
329 #define ocs_strcmp(d,s)			strcmp(d,s)
330 #define ocs_strcasecmp(d,s)		strcasecmp(d,s)
331 #define ocs_strncmp(d,s,n)		strncmp(d,s,n)
332 #define ocs_strstr(h,n)			strstr(h,n)
333 #define ocs_strsep(h, n)		strsep(h, n)
334 #define ocs_strchr(s,c)			strchr(s,c)
335 #define ocs_copy_from_user(dst, src, n)	copyin(src, dst, n)
336 #define ocs_copy_to_user(dst, src, n)	copyout(src, dst, n)
337 #define ocs_snprintf(buf, n, fmt, ...)	snprintf(buf, n, fmt, ##__VA_ARGS__)
338 #define ocs_vsnprintf(buf, n, fmt, ap)	vsnprintf((char*)buf, n, fmt, ap)
339 #define ocs_sscanf(buf,fmt, ...)	sscanf(buf, fmt, ##__VA_ARGS__)
340 #define ocs_printf			printf
341 #define ocs_isspace(c)			isspace(c)
342 #define ocs_isdigit(c)			isdigit(c)
343 #define ocs_isxdigit(c)			isxdigit(c)
344 
345 extern uint64_t ocs_get_tsc(void);
346 extern void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size);
347 extern int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size);
348 extern void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size);
349 extern char *ocs_strdup(const char *s);
350 
351 /**
352  * @ingroup os
353  * @brief Set the value of each byte in memory
354  *
355  * @param b pointer to the memory
356  * @param c value used to set memory
357  * @param l number of bytes to set
358  *
359  * @return original value of mem pointer
360  */
361 #define ocs_memset(b, c, l) memset(b, c, l)
362 
363 #define LOG_CRIT	0
364 #define LOG_ERR		1
365 #define LOG_WARN	2
366 #define LOG_INFO	3
367 #define LOG_TEST	4
368 #define LOG_DEBUG	5
369 
370 extern int loglevel;
371 
372 extern void _ocs_log(ocs_t *ocs, const char *func, int line, const char *fmt, ...);
373 
374 #define ocs_log_crit(os, fmt, ...)	ocs_log(os, LOG_CRIT, fmt, ##__VA_ARGS__);
375 #define ocs_log_err(os, fmt, ...)	ocs_log(os, LOG_ERR, fmt, ##__VA_ARGS__);
376 #define ocs_log_warn(os, fmt, ...)	ocs_log(os, LOG_WARN, fmt, ##__VA_ARGS__);
377 #define ocs_log_info(os, fmt, ...)	ocs_log(os, LOG_INFO, fmt, ##__VA_ARGS__);
378 #define ocs_log_test(os, fmt, ...)	ocs_log(os, LOG_TEST, fmt, ##__VA_ARGS__);
379 #define ocs_log_debug(os, fmt, ...)	ocs_log(os, LOG_DEBUG, fmt, ##__VA_ARGS__);
380 
381 #define ocs_log(os, level, fmt, ...)                    \
382 	do {                                            \
383 		if (level <= loglevel) {                \
384 			_ocs_log(os, __func__, __LINE__, fmt, ##__VA_ARGS__);   \
385 		}                                       \
386 	} while (0)
387 
388 static inline uint32_t ocs_roundup(uint32_t x, uint32_t y)
389 {
390 	return (((x + y - 1) / y) * y);
391 }
392 
393 static inline uint32_t ocs_rounddown(uint32_t x, uint32_t y)
394 {
395 	return ((x / y) * y);
396 }
397 
398 /***************************************************************************
399  * Memory allocation interfaces
400  */
401 
402 #define OCS_M_ZERO	M_ZERO
403 #define OCS_M_NOWAIT	M_NOWAIT
404 
405 /**
406  * @ingroup os
407  * @brief Allocate host memory
408  *
409  * @param os OS handle
410  * @param size number of bytes to allocate
411  * @param flags additional options
412  *
413  * Flags include
414  *  - OCS_M_ZERO zero memory after allocating
415  *  - OCS_M_NOWAIT do not block/sleep waiting for an allocation request
416  *
417  * @return pointer to allocated memory, NULL otherwise
418  */
419 extern void *ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags);
420 
421 /**
422  * @ingroup os
423  * @brief Free host memory
424  *
425  * @param os OS handle
426  * @param addr pointer to memory
427  * @param size bytes to free
428  */
429 extern void ocs_free(ocs_os_handle_t os, void *addr, size_t size);
430 
431 /**
432  * @ingroup os
433  * @brief generic DMA memory descriptor for driver allocations
434  *
435  * Memory regions ultimately used by the hardware are described using
436  * this structure. All implementations must include the structure members
437  * defined in the first section, and they may also add their own structure
438  * members in the second section.
439  *
440  * Note that each region described by ocs_dma_s is assumed to be physically
441  * contiguous.
442  */
443 typedef struct ocs_dma_s {
444 	/*
445 	 * OCS layer requires the following members
446 	 */
447 	void		*virt;	/**< virtual address of the memory used by the CPU */
448 	void		*alloc;	/**< originally allocated virtual address used to restore virt if modified */
449 	uintptr_t	phys;	/**< physical or bus address of the memory used by the hardware */
450 	size_t		size;	/**< size in bytes of the memory */
451 	/*
452 	 * Implementation specific fields allowed here
453 	 */
454 	size_t		len;	/**< application specific length */
455 	bus_dma_tag_t	tag;
456 	bus_dmamap_t	map;
457 } ocs_dma_t;
458 
459 /**
460  * @ingroup os
461  * @brief Returns maximum supported DMA allocation size
462  *
463  * @param os OS specific handle or driver context
464  * @param align alignment requirement for DMA allocation
465  *
466  * Return maximum supported DMA allocation size, given alignment
467  * requirement.
468  *
469  * @return maxiumum supported DMA allocation size
470  */
471 static inline uint32_t ocs_max_dma_alloc(ocs_os_handle_t os, size_t align)
472 {
473 	return ~((uint32_t)0); /* no max */
474 }
475 
476 /**
477  * @ingroup os
478  * @brief Allocate a DMA capable block of memory
479  *
480  * @param os OS specific handle or driver context
481  * @param dma DMA descriptor containing results of memory allocation
482  * @param size Size in bytes of desired allocation
483  * @param align Alignment in bytes of the requested allocation
484  *
485  * @return 0 on success, non-zero otherwise
486  */
487 extern int32_t ocs_dma_alloc(ocs_os_handle_t, ocs_dma_t *, size_t, size_t);
488 
489 /**
490  * @ingroup os
491  * @brief Free a DMA capable block of memory
492  *
493  * @param os OS specific handle or driver context
494  * @param dma DMA descriptor for memory to be freed
495  *
496  * @return 0 if memory is de-allocated, non-zero otherwise
497  */
498 extern int32_t ocs_dma_free(ocs_os_handle_t, ocs_dma_t *);
499 extern int32_t ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
500 extern int32_t ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
501 
502 static inline int32_t ocs_dma_valid(ocs_dma_t *dma)
503 {
504 	return (dma->size != 0);
505 }
506 
507 /**
508  * @ingroup os
509  * @brief Synchronize the DMA buffer memory
510  *
511  * Ensures memory coherency between the CPU and device
512  *
513  * @param dma DMA descriptor of memory to synchronize
514  * @param flags Describes direction of synchronization
515  *   - OCS_DMASYNC_PREREAD sync needed before hardware updates host memory
516  *   - OCS_DMASYNC_PREWRITE sync needed after CPU updates host memory but before hardware can access
517  *   - OCS_DMASYNC_POSTREAD sync needed after hardware updates host memory but before CPU can access
518  *   - OCS_DMASYNC_POSTWRITE sync needed after hardware updates host memory
519  */
520 extern void ocs_dma_sync(ocs_dma_t *, uint32_t);
521 
522 #define OCS_DMASYNC_PREWRITE BUS_DMASYNC_PREWRITE
523 #define OCS_DMASYNC_POSTREAD BUS_DMASYNC_POSTREAD
524 
525 
526 /***************************************************************************
527  * Locking
528  */
529 
530 /**
531  * @ingroup os
532  * @typedef ocs_lock_t
533  * @brief Define the type used implement locking
534  */
535 #define MAX_LOCK_DESC_LEN	64
536 typedef struct ocs_lock_s {
537 	struct	mtx lock;
538 	char	name[MAX_LOCK_DESC_LEN];
539 } ocs_lock_t;
540 
541 /**
542  * @ingroup os
543  * @brief Initialize a lock
544  *
545  * @param lock lock to initialize
546  * @param name string identifier for the lock
547  */
548 extern void ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...);
549 
550 /**
551  * @ingroup os
552  * @brief Free a previously allocated lock
553  *
554  * @param lock lock to free
555  */
556 static inline void
557 ocs_lock_free(ocs_lock_t *lock)
558 {
559 
560 	if (mtx_initialized(&(lock)->lock)) {
561 		mtx_assert(&(lock)->lock, MA_NOTOWNED);
562 		mtx_destroy(&(lock)->lock);
563 	} else {
564 		panic("XXX trying to free with un-initialized mtx!?!?\n");
565 	}
566 }
567 
568 /**
569  * @ingroup os
570  * @brief Acquire a lock
571  *
572  * @param lock lock to obtain
573  */
574 static inline void
575 ocs_lock(ocs_lock_t *lock)
576 {
577 
578 	if (mtx_initialized(&(lock)->lock)) {
579 		mtx_assert(&(lock)->lock, MA_NOTOWNED);
580 		mtx_lock(&(lock)->lock);
581 	} else {
582 		panic("XXX trying to lock with un-initialized mtx!?!?\n");
583 	}
584 }
585 
586 /**
587  * @ingroup os
588  * @brief Release a lock
589  *
590  * @param lock lock to release
591  */
592 static inline void
593 ocs_unlock(ocs_lock_t *lock)
594 {
595 
596 	if (mtx_initialized(&(lock)->lock)) {
597 		mtx_assert(&(lock)->lock, MA_OWNED | MA_NOTRECURSED);
598 		mtx_unlock(&(lock)->lock);
599 	} else {
600 		panic("XXX trying to unlock with un-initialized mtx!?!?\n");
601 	}
602 }
603 
604 /**
605  * @ingroup os
606  * @typedef ocs_lock_t
607  * @brief Define the type used implement recursive locking
608  */
609 typedef struct ocs_lock_s ocs_rlock_t;
610 
611 /**
612  * @ingroup os
613  * @brief Initialize a recursive lock
614  *
615  * @param ocs pointer to ocs structure
616  * @param lock lock to initialize
617  * @param name string identifier for the lock
618  */
619 static inline void
620 ocs_rlock_init(ocs_t *ocs, ocs_rlock_t *lock, const char *name)
621 {
622 	ocs_strncpy(lock->name, name, MAX_LOCK_DESC_LEN);
623 	mtx_init(&(lock)->lock, lock->name, NULL, MTX_DEF | MTX_RECURSE | MTX_DUPOK);
624 }
625 
626 /**
627  * @ingroup os
628  * @brief Free a previously allocated recursive lock
629  *
630  * @param lock lock to free
631  */
632 static inline void
633 ocs_rlock_free(ocs_rlock_t *lock)
634 {
635 	if (mtx_initialized(&(lock)->lock)) {
636 		mtx_destroy(&(lock)->lock);
637 	} else {
638 		panic("XXX trying to free with un-initialized mtx!?!?\n");
639 	}
640 }
641 
642 /**
643  * @brief try to acquire a recursive lock
644  *
645  * Attempt to acquire a recursive lock, return TRUE if successful
646  *
647  * @param lock pointer to recursive lock
648  *
649  * @return TRUE if lock was acquired, FALSE if not
650  */
651 static inline int32_t
652 ocs_rlock_try(ocs_rlock_t *lock)
653 {
654 	int rc = mtx_trylock(&(lock)->lock);
655 
656 	return rc != 0;
657 }
658 
659 /**
660  * @ingroup os
661  * @brief Acquire a recursive lock
662  *
663  * @param lock lock to obtain
664  */
665 static inline void
666 ocs_rlock_acquire(ocs_rlock_t *lock)
667 {
668 	if (mtx_initialized(&(lock)->lock)) {
669 		mtx_lock(&(lock)->lock);
670 	} else {
671 		panic("XXX trying to lock with un-initialized mtx!?!?\n");
672 	}
673 }
674 
675 /**
676  * @ingroup os
677  * @brief Release a recursive lock
678  *
679  * @param lock lock to release
680  */
681 static inline void
682 ocs_rlock_release(ocs_rlock_t *lock)
683 {
684 	if (mtx_initialized(&(lock)->lock)) {
685 		mtx_assert(&(lock)->lock, MA_OWNED);
686 		mtx_unlock(&(lock)->lock);
687 	} else {
688 		panic("XXX trying to unlock with un-initialized mtx!?!?\n");
689 	}
690 }
691 
692 /**
693  * @brief counting semaphore
694  *
695  * Declaration of the counting semaphore object
696  *
697  */
698 typedef struct {
699 	char name[32];
700 	struct sema sem;		/**< OS counting semaphore structure */
701 } ocs_sem_t;
702 
703 #define OCS_SEM_FOREVER		(-1)
704 #define OCS_SEM_TRY		(0)
705 
706 /**
707  * @brief Initialize a counting semaphore
708  *
709  * The semaphore is initiatlized to the value
710  *
711  * @param sem pointer to semaphore
712  * @param val initial value
713  * @param name label for the semaphore
714  *
715  * @return returns 0 for success, a negative error code value for failure.
716  */
717 
718 extern int ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) __attribute__((format(printf, 3, 4)));
719 
720 /**
721  * @brief execute a P (decrement) operation
722  *
723  * A P (decrement and block if negative) operation is performed on the semaphore.
724  *
725  * If timeout_usec is zero, the semaphore attempts one time and returns 0 if acquired.
726  * If timeout_usec is greater than zero, then the call will block until the semaphore
727  * is acquired, or a timeout occurred.  If timeout_usec is less than zero, then
728  * the call will block until the semaphore is acquired.
729  *
730  * @param sem pointer to semaphore
731  * @param timeout_usec timeout in microseconds
732  *
733  * @return returns 0 for success, negative value if the semaphore was not acquired.
734  */
735 
736 static inline int
737 ocs_sem_p(ocs_sem_t *sem, int timeout_usec)
738 {
739 	int32_t rc = 0;
740 
741 	if (timeout_usec == 0) {
742 		rc = sema_trywait(&sem->sem);
743 		if (rc == 0) {
744 			rc = -1;
745 		}
746 	} else if (timeout_usec > 0) {
747 		struct timeval tv;
748 		uint32_t ticks;
749 
750 		tv.tv_sec = timeout_usec / 1000000;
751 		tv.tv_usec = timeout_usec % 1000000;
752 		ticks = tvtohz(&tv);
753 		if (ticks == 0) {
754 			ticks ++;
755 		}
756 		rc = sema_timedwait(&sem->sem, ticks);
757 		if (rc != 0) {
758 			rc = -1;
759 		}
760 	} else {
761 		sema_wait(&sem->sem);
762 	}
763 	if (rc)
764 		rc = -1;
765 
766 	return rc;
767 }
768 
769 /**
770  * @brief perform a V (increment) operation on a counting semaphore
771  *
772  * The semaphore is incremented, unblocking one thread that is waiting on the
773  * sempahore
774  *
775  * @param sem pointer to the semaphore
776  *
777  * @return none
778  */
779 
780 static inline void
781 ocs_sem_v(ocs_sem_t *sem)
782 {
783 	sema_post(&sem->sem);
784 }
785 
786 /***************************************************************************
787  * Bitmap
788  */
789 
790 /**
791  * @ingroup os
792  * @typedef ocs_bitmap_t
793  * @brief Define the type used implement bit-maps
794  */
795 typedef bitstr_t ocs_bitmap_t;
796 
797 /**
798  * @ingroup os
799  * @brief Allocate a bitmap
800  *
801  * @param n_bits Minimum number of entries in the bit-map
802  *
803  * @return pointer to the bit-map or NULL on error
804  */
805 extern ocs_bitmap_t *ocs_bitmap_alloc(uint32_t n_bits);
806 
807 /**
808  * @ingroup os
809  * @brief Free a bit-map
810  *
811  * @param bitmap Bit-map to free
812  */
813 extern void ocs_bitmap_free(ocs_bitmap_t *bitmap);
814 
815 /**
816  * @ingroup os
817  * @brief Find next unset bit and set it
818  *
819  * @param bitmap bit map to search
820  * @param n_bits number of bits in map
821  *
822  * @return bit position or -1 if map is full
823  */
824 extern int32_t ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits);
825 
826 /**
827  * @ingroup os
828  * @brief search for next (un)set bit
829  *
830  * @param bitmap bit map to search
831  * @param set search for a set or unset bit
832  * @param n_bits number of bits in map
833  *
834  * @return bit position or -1
835  */
836 extern int32_t ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits);
837 
838 /**
839  * @ingroup os
840  * @brief clear the specified bit
841  *
842  * @param bitmap pointer to bit map
843  * @param bit bit number to clear
844  */
845 extern void ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit);
846 
847 extern int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len);
848 
849 /***************************************************************************
850  * Timer Routines
851  *
852  * Functions for setting, querying and canceling timers.
853  */
854 typedef struct {
855 	struct callout	callout;
856 	struct mtx	lock;
857 
858 	void	(*func)(void *);
859 	void	*data;
860 } ocs_timer_t;
861 
862 /**
863  * @ingroup os
864  * @brief Initialize and set a timer
865  *
866  * @param os OS handle
867  * @param timer    pointer to the structure allocated for this timer
868  * @param func     the function to call when the timer expires
869  * @param data     Data to pass to the provided timer function when the timer
870  *                 expires.
871  * @param timeout_ms the timeout in milliseconds
872  */
873 extern int32_t ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg),
874 			       void *data, uint32_t timeout_ms);
875 
876 /**
877  * @ingroup os
878  * @brief Modify a timer's expiration
879  *
880  * @param timer    pointer to the structure allocated for this timer
881  * @param timeout_ms the timeout in milliseconds
882  */
883 extern int32_t ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms);
884 
885 /**
886  * @ingroup os
887  * @brief Queries to see if a timer is pending.
888  *
889  * @param timer    pointer to the structure allocated for this timer
890  *
891  * @return non-zero if the timer is pending
892  */
893 extern int32_t ocs_timer_pending(ocs_timer_t *timer);
894 
895 /**
896  * @ingroup os
897  * @brief Remove a pending timer
898  *
899  * @param timer    pointer to the structure allocated for this timer
900  *                 expires.
901  */
902 extern int32_t ocs_del_timer(ocs_timer_t *timer);
903 
904 /***************************************************************************
905  * Atomics
906  *
907  */
908 
909 typedef uint32_t ocs_atomic_t;
910 
911 /**
912  * @ingroup os
913  * @brief initialize an atomic
914  *
915  * @param a    pointer to the atomic object
916  * @param v    initial value
917  *
918  * @return none
919  */
920 #define ocs_atomic_init(a, v)	ocs_atomic_set(a, v)
921 
922 /**
923  * @ingroup os
924  * @brief adds an integer to an atomic value
925  *
926  * @param a    pointer to the atomic object
927  * @param v    value to increment
928  *
929  * @return the value of the atomic before incrementing.
930  */
931 #define ocs_atomic_add_return(a, v)	atomic_fetchadd_32(a, v)
932 
933 /**
934  * @ingroup os
935  * @brief subtracts an integer to an atomic value
936  *
937  * @param a    pointer to the atomic object
938  * @param v    value to increment
939  *
940  * @return the value of the atomic before subtracting.
941  */
942 #define ocs_atomic_sub_return(a, v)     atomic_fetchadd_32(a, (-(v)))
943 
944 /**
945  * @ingroup os
946  * @brief returns the current value of an atomic object
947  *
948  * @param a    pointer to the atomic object
949  *
950  * @return the value of the atomic.
951  */
952 #define ocs_atomic_read(a)		atomic_load_acq_32(a)
953 
954 /**
955  * @ingroup os
956  * @brief sets the current value of an atomic object
957  *
958  * @param a    pointer to the atomic object
959  */
960 #define ocs_atomic_set(a, v)		atomic_store_rel_32(a, v)
961 
962 /**
963  * @ingroup os
964  * @brief Sets atomic to 0, returns previous value
965  *
966  * @param a    pointer to the atomic object
967  *
968  * @return the value of the atomic before the operation.
969  */
970 #define ocs_atomic_read_and_clear	atomic_readandclear_32(a)
971 
972 /**
973  * @brief OCS thread structure
974  *
975  */
976 
977 typedef struct ocs_thread_s ocs_thread_t;
978 
979 typedef int32_t (*ocs_thread_fctn)(ocs_thread_t *mythread);
980 
981 struct ocs_thread_s  {
982 	struct thread *tcb;			/*<< thread control block */
983 	ocs_thread_fctn fctn;			/*<< thread function */
984 	char *name;				/*<< name of thread */
985 	void *arg;				/*<< pointer to thread argument */
986 	ocs_atomic_t terminate;			/*<< terminate request */
987 	int32_t retval;				/*<< return value */
988 	uint32_t cpu_affinity;			/*<< cpu affinity */
989 };
990 #define OCS_THREAD_DEFAULT_STACK_SIZE_PAGES	8
991 
992 /**
993  * @brief OCS thread start options
994  *
995  */
996 
997 typedef enum {
998 	OCS_THREAD_RUN,				/*<< run immediately */
999 	OCS_THREAD_CREATE,			/*<< create and wait for start request */
1000 } ocs_thread_start_e;
1001 
1002 
1003 extern int32_t ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn,
1004 				 const char *name, void *arg, ocs_thread_start_e start_option);
1005 extern int32_t ocs_thread_start(ocs_thread_t *thread);
1006 extern void *ocs_thread_get_arg(ocs_thread_t *mythread);
1007 extern int32_t ocs_thread_terminate(ocs_thread_t *thread);
1008 extern int32_t ocs_thread_terminate_requested(ocs_thread_t *thread);
1009 extern int32_t ocs_thread_get_retval(ocs_thread_t *thread);
1010 extern void ocs_thread_yield(ocs_thread_t *thread);
1011 extern ocs_thread_t *ocs_thread_self(void);
1012 extern int32_t ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu);
1013 extern int32_t ocs_thread_getcpu(void);
1014 
1015 
1016 /***************************************************************************
1017  * PCI
1018  *
1019  * Several functions below refer to a "register set". This is one or
1020  * more PCI BARs that constitute a PCI address. For example, if a MMIO
1021  * region is described using both BAR[0] and BAR[1], the combination of
1022  * BARs defines register set 0.
1023  */
1024 
1025 /**
1026  * @brief tracks mapped PCI memory regions
1027  */
1028 typedef struct ocs_pci_reg_s {
1029 	uint32_t		rid;
1030 	struct resource		*res;
1031 	bus_space_tag_t		btag;
1032 	bus_space_handle_t	bhandle;
1033 } ocs_pci_reg_t;
1034 
1035 #define PCI_MAX_BAR				6
1036 #define PCI_64BIT_BAR0				0
1037 
1038 #define PCI_VENDOR_EMULEX       		0x10df		/* Emulex */
1039 
1040 #define PCI_PRODUCT_EMULEX_OCE16001		0xe200		/* OneCore 16Gb FC (lancer) */
1041 #define PCI_PRODUCT_EMULEX_OCE16002		0xe200		/* OneCore 16Gb FC (lancer) */
1042 #define PCI_PRODUCT_EMULEX_LPE31004		0xe300  /* LightPulse 16Gb x 4 FC (lancer-g6) */
1043 #define PCI_PRODUCT_EMULEX_LPE32002		0xe300  /* LightPulse 32Gb x 2 FC (lancer-g6) */
1044 #define PCI_PRODUCT_EMULEX_OCE1600_VF		0xe208
1045 #define PCI_PRODUCT_EMULEX_OCE50102		0xe260		/* OneCore FCoE (lancer) */
1046 #define PCI_PRODUCT_EMULEX_OCE50102_VF		0xe268
1047 
1048 /**
1049  * @ingroup os
1050  * @brief Get the PCI bus, device, and function values
1051  *
1052  * @param ocs OS specific handle or driver context
1053  * @param bus Pointer to location to store the bus number.
1054  * @param dev Pointer to location to store the device number.
1055  * @param func Pointer to location to store the function number.
1056  *
1057  * @return Returns 0.
1058  */
1059 extern int32_t
1060 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
1061 
1062 extern ocs_t *ocs_get_instance(uint32_t index);
1063 extern uint32_t ocs_instance(void *os);
1064 
1065 
1066 /**
1067  * @ingroup os
1068  * @brief Read a 32 bit value from the specified configuration register
1069  *
1070  * @param os OS specific handle or driver context
1071  * @param reg register offset
1072  *
1073  * @return The 32 bit value
1074  */
1075 extern uint32_t ocs_config_read32(ocs_os_handle_t os, uint32_t reg);
1076 
1077 /**
1078  * @ingroup os
1079  * @brief Read a 16 bit value from the specified configuration
1080  *        register
1081  *
1082  * @param os OS specific handle or driver context
1083  * @param reg register offset
1084  *
1085  * @return The 16 bit value
1086  */
1087 extern uint16_t ocs_config_read16(ocs_os_handle_t os, uint32_t reg);
1088 
1089 /**
1090  * @ingroup os
1091  * @brief Read a 8 bit value from the specified configuration
1092  *        register
1093  *
1094  * @param os OS specific handle or driver context
1095  * @param reg register offset
1096  *
1097  * @return The 8 bit value
1098  */
1099 extern uint8_t ocs_config_read8(ocs_os_handle_t os, uint32_t reg);
1100 
1101 /**
1102  * @ingroup os
1103  * @brief Write a 8 bit value to the specified configuration
1104  *        register
1105  *
1106  * @param os OS specific handle or driver context
1107  * @param reg register offset
1108  * @param val value to write
1109  *
1110  * @return None
1111  */
1112 extern void ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val);
1113 
1114 /**
1115  * @ingroup os
1116  * @brief Write a 16 bit value to the specified configuration
1117  *        register
1118  *
1119  * @param os OS specific handle or driver context
1120  * @param reg register offset
1121  * @param val value to write
1122  *
1123  * @return None
1124  */
1125 extern void ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val);
1126 
1127 /**
1128  * @ingroup os
1129  * @brief Write a 32 bit value to the specified configuration
1130  *        register
1131  *
1132  * @param os OS specific handle or driver context
1133  * @param reg register offset
1134  * @param val value to write
1135  *
1136  * @return None
1137  */
1138 extern void ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val);
1139 
1140 /**
1141  * @ingroup os
1142  * @brief Read a PCI register
1143  *
1144  * @param os OS specific handle or driver context
1145  * @param rset Which "register set" to use
1146  * @param off  Register offset
1147  *
1148  * @return 32 bit conents of the register
1149  */
1150 extern uint32_t ocs_reg_read32(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1151 
1152 /**
1153  * @ingroup os
1154  * @brief Read a PCI register
1155  *
1156  * @param os OS specific handle or driver context
1157  * @param rset Which "register set" to use
1158  * @param off  Register offset
1159  *
1160  * @return 16 bit conents of the register
1161  */
1162 extern uint16_t ocs_reg_read16(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1163 
1164 /**
1165  * @ingroup os
1166  * @brief Read a PCI register
1167  *
1168  * @param os OS specific handle or driver context
1169  * @param rset Which "register set" to use
1170  * @param off  Register offset
1171  *
1172  * @return 8 bit conents of the register
1173  */
1174 extern uint8_t ocs_reg_read8(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1175 
1176 /**
1177  * @ingroup os
1178  * @brief Write a PCI register
1179  *
1180  * @param os OS specific handle or driver context
1181  * @param rset Which "register set" to use
1182  * @param off  Register offset
1183  * @param val  32-bit value to write
1184  */
1185 extern void ocs_reg_write32(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint32_t val);
1186 
1187 /**
1188  * @ingroup os
1189  * @brief Write a PCI register
1190  *
1191  * @param os OS specific handle or driver context
1192  * @param rset Which "register set" to use
1193  * @param off  Register offset
1194  * @param val  16-bit value to write
1195  */
1196 extern void ocs_reg_write16(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint16_t val);
1197 
1198 /**
1199  * @ingroup os
1200  * @brief Write a PCI register
1201  *
1202  * @param os OS specific handle or driver context
1203  * @param rset Which "register set" to use
1204  * @param off  Register offset
1205  * @param val  8-bit value to write
1206  */
1207 extern void ocs_reg_write8(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint8_t val);
1208 
1209 /**
1210  * @ingroup os
1211  * @brief Disable interrupts
1212  *
1213  * @param os OS specific handle or driver context
1214  */
1215 extern void ocs_intr_disable(ocs_os_handle_t os);
1216 
1217 /**
1218  * @ingroup os
1219  * @brief Enable interrupts
1220  *
1221  * @param os OS specific handle or driver context
1222  */
1223 extern void ocs_intr_enable(ocs_os_handle_t os);
1224 
1225 /**
1226  * @ingroup os
1227  * @brief Return model string
1228  *
1229  * @param os OS specific handle or driver context
1230  */
1231 extern const char *ocs_pci_model(uint16_t vendor, uint16_t device);
1232 
1233 extern void ocs_print_stack(void);
1234 
1235 extern void ocs_abort(void) __attribute__((noreturn));
1236 
1237 /***************************************************************************
1238  * Reference counting
1239  *
1240  */
1241 
1242 /**
1243  * @ingroup os
1244  * @brief reference counter object
1245  */
1246 typedef void (*ocs_ref_release_t)(void *arg);
1247 typedef struct ocs_ref_s {
1248 	ocs_ref_release_t release; /* release function to call */
1249 	void *arg;
1250 	uint32_t count;		/* ref count; no need to be atomic if we have a lock */
1251 } ocs_ref_t;
1252 
1253 /**
1254  * @ingroup os
1255  * @brief initialize given reference object
1256  *
1257  * @param ref Pointer to reference object
1258  * @param release Function to be called when count is 0.
1259  * @param arg Argument to be passed to release function.
1260  */
1261 static inline void
1262 ocs_ref_init(ocs_ref_t *ref, ocs_ref_release_t release, void *arg)
1263 {
1264 	ref->release = release;
1265 	ref->arg = arg;
1266 	ocs_atomic_init(&ref->count, 1);
1267 }
1268 
1269 /**
1270  * @ingroup os
1271  * @brief Return reference count value
1272  *
1273  * @param ref Pointer to reference object
1274  *
1275  * @return Count value of given reference object
1276  */
1277 static inline uint32_t
1278 ocs_ref_read_count(ocs_ref_t *ref)
1279 {
1280 	return ocs_atomic_read(&ref->count);
1281 }
1282 
1283 /**
1284  * @ingroup os
1285  * @brief Set count on given reference object to a value.
1286  *
1287  * @param ref Pointer to reference object
1288  * @param i Set count to this value
1289  */
1290 static inline void
1291 ocs_ref_set(ocs_ref_t *ref, int i)
1292 {
1293 	ocs_atomic_set(&ref->count, i);
1294 }
1295 
1296 /**
1297  * @ingroup os
1298  * @brief Take a reference on given object.
1299  *
1300  * @par Description
1301  * This function takes a reference on an object.
1302  *
1303  * Note: this function should only be used if the caller can
1304  * guarantee that the reference count is >= 1 and will stay >= 1
1305  * for the duration of this call (i.e. won't go to zero). If it
1306  * can't (the refcount may go to zero during this call),
1307  * ocs_ref_get_unless_zero() should be used instead.
1308  *
1309  * @param ref Pointer to reference object
1310  *
1311  */
1312 static inline void
1313 ocs_ref_get(ocs_ref_t *ref)
1314 {
1315 	ocs_atomic_add_return(&ref->count, 1);
1316 }
1317 
1318 /**
1319  * @ingroup os
1320  * @brief Take a reference on given object if count is not zero.
1321  *
1322  * @par Description
1323  * This function takes a reference on an object if and only if
1324  * the given reference object is "active" or valid.
1325  *
1326  * @param ref Pointer to reference object
1327  *
1328  * @return non-zero if "get" succeeded; Return zero if ref count
1329  * is zero.
1330  */
1331 static inline uint32_t
1332 ocs_ref_get_unless_zero(ocs_ref_t *ref)
1333 {
1334 	uint32_t rc = 0;
1335 	rc = ocs_atomic_read(&ref->count);
1336 		if (rc != 0) {
1337 			ocs_atomic_add_return(&ref->count, 1);
1338 		}
1339 	return rc;
1340 }
1341 
1342 /**
1343  * @ingroup os
1344  * @brief Decrement reference on given object
1345  *
1346  * @par Description
1347  * This function decrements the reference count on the given
1348  * reference object. If the reference count becomes zero, the
1349  * "release" function (set during "init" time) is called.
1350  *
1351  * @param ref Pointer to reference object
1352  *
1353  * @return non-zero if release function was called; zero
1354  * otherwise.
1355  */
1356 static inline uint32_t
1357 ocs_ref_put(ocs_ref_t *ref)
1358 {
1359 	uint32_t rc = 0;
1360 	if (ocs_atomic_sub_return(&ref->count, 1) == 1) {
1361 		ref->release(ref->arg);
1362 		rc = 1;
1363 	}
1364 	return rc;
1365 }
1366 
1367 /**
1368  * @ingroup os
1369  * @brief Get the OS system ticks
1370  *
1371  * @return number of ticks that have occurred since the system
1372  * booted.
1373  */
1374 static inline uint64_t
1375 ocs_get_os_ticks(void)
1376 {
1377 	return ticks;
1378 }
1379 
1380 /**
1381  * @ingroup os
1382  * @brief Get the OS system tick frequency
1383  *
1384  * @return frequency of system ticks.
1385  */
1386 static inline uint32_t
1387 ocs_get_os_tick_freq(void)
1388 {
1389 	return hz;
1390 }
1391 
1392 /*****************************************************************************
1393  *
1394  * CPU topology API
1395  */
1396 
1397 typedef struct {
1398 	uint32_t num_cpus;	/* Number of CPU cores */
1399 	uint8_t hyper;		/* TRUE if threaded CPUs */
1400 } ocs_cpuinfo_t;
1401 
1402 extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo);
1403 extern uint32_t ocs_get_num_cpus(void);
1404 
1405 #include "ocs_list.h"
1406 #include "ocs_utils.h"
1407 #include "ocs_mgmt.h"
1408 #include "ocs_common.h"
1409 
1410 #endif /* !_OCS_OS_H */
1411