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