xref: /freebsd/sys/dev/ocs_fc/ocs_os.c (revision d7d962ead0b6e5e8a39202d0590022082bf5bfb6)
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  * Implementation of common BSD OS abstraction functions
37  */
38 
39 #include "ocs.h"
40 
41 static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
42 
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
45 
46 #include <machine/bus.h>
47 
48 callout_func_t	__ocs_callout;
49 
50 uint32_t
51 ocs_config_read32(ocs_os_handle_t os, uint32_t reg)
52 {
53 	return pci_read_config(os->dev, reg, 4);
54 }
55 
56 uint16_t
57 ocs_config_read16(ocs_os_handle_t os, uint32_t reg)
58 {
59 	return pci_read_config(os->dev, reg, 2);
60 }
61 
62 uint8_t
63 ocs_config_read8(ocs_os_handle_t os, uint32_t reg)
64 {
65 	return pci_read_config(os->dev, reg, 1);
66 }
67 
68 void
69 ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val)
70 {
71 	return pci_write_config(os->dev, reg, val, 1);
72 }
73 
74 void
75 ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val)
76 {
77 	return pci_write_config(os->dev, reg, val, 2);
78 }
79 
80 void
81 ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val)
82 {
83 	return pci_write_config(os->dev, reg, val, 4);
84 }
85 
86 /**
87  * @ingroup os
88  * @brief Read a 32bit PCI register
89  *
90  * The SLI documentation uses the term "register set" to describe one or more
91  * PCI BARs which form a logical address. For example, a 64-bit address uses
92  * two BARs, and thus constitute a register set.
93  *
94  * @param ocs Pointer to the driver's context
95  * @param rset Register Set to use
96  * @param off Offset from the base address of the Register Set
97  *
98  * @return register value
99  */
100 uint32_t
101 ocs_reg_read32(ocs_t *ocs, uint32_t rset, uint32_t off)
102 {
103 	ocs_pci_reg_t		*reg = NULL;
104 
105 	reg = &ocs->reg[rset];
106 
107 	return bus_space_read_4(reg->btag, reg->bhandle, off);
108 }
109 
110 /**
111  * @ingroup os
112  * @brief Read a 16bit PCI register
113  *
114  * The SLI documentation uses the term "register set" to describe one or more
115  * PCI BARs which form a logical address. For example, a 64-bit address uses
116  * two BARs, and thus constitute a register set.
117  *
118  * @param ocs Pointer to the driver's context
119  * @param rset Register Set to use
120  * @param off Offset from the base address of the Register Set
121  *
122  * @return register value
123  */
124 uint16_t
125 ocs_reg_read16(ocs_t *ocs, uint32_t rset, uint32_t off)
126 {
127 	ocs_pci_reg_t		*reg = NULL;
128 
129 	reg = &ocs->reg[rset];
130 
131 	return bus_space_read_2(reg->btag, reg->bhandle, off);
132 }
133 
134 /**
135  * @ingroup os
136  * @brief Read a 8bit PCI register
137  *
138  * The SLI documentation uses the term "register set" to describe one or more
139  * PCI BARs which form a logical address. For example, a 64-bit address uses
140  * two BARs, and thus constitute a register set.
141  *
142  * @param ocs Pointer to the driver's context
143  * @param rset Register Set to use
144  * @param off Offset from the base address of the Register Set
145  *
146  * @return register value
147  */
148 uint8_t
149 ocs_reg_read8(ocs_t *ocs, uint32_t rset, uint32_t off)
150 {
151 	ocs_pci_reg_t		*reg = NULL;
152 
153 	reg = &ocs->reg[rset];
154 
155 	return bus_space_read_1(reg->btag, reg->bhandle, off);
156 }
157 
158 /**
159  * @ingroup os
160  * @brief Write a 32bit PCI register
161  *
162  * The SLI documentation uses the term "register set" to describe one or more
163  * PCI BARs which form a logical address. For example, a 64-bit address uses
164  * two BARs, and thus constitute a register set.
165  *
166  * @param ocs Pointer to the driver's context
167  * @param rset Register Set to use
168  * @param off Offset from the base address of the Register Set
169  * @param val Value to write
170  *
171  * @return none
172  */
173 void
174 ocs_reg_write32(ocs_t *ocs, uint32_t rset, uint32_t off, uint32_t val)
175 {
176 	ocs_pci_reg_t		*reg = NULL;
177 
178 	reg = &ocs->reg[rset];
179 
180 	return bus_space_write_4(reg->btag, reg->bhandle, off, val);
181 }
182 
183 /**
184  * @ingroup os
185  * @brief Write a 16-bit PCI register
186  *
187  * The SLI documentation uses the term "register set" to describe one or more
188  * PCI BARs which form a logical address. For example, a 64-bit address uses
189  * two BARs, and thus constitute a register set.
190  *
191  * @param ocs Pointer to the driver's context
192  * @param rset Register Set to use
193  * @param off Offset from the base address of the Register Set
194  * @param val Value to write
195  *
196  * @return none
197  */
198 void
199 ocs_reg_write16(ocs_t *ocs, uint32_t rset, uint32_t off, uint16_t val)
200 {
201 	ocs_pci_reg_t		*reg = NULL;
202 
203 	reg = &ocs->reg[rset];
204 
205 	return bus_space_write_2(reg->btag, reg->bhandle, off, val);
206 }
207 
208 /**
209  * @ingroup os
210  * @brief Write a 8-bit PCI register
211  *
212  * The SLI documentation uses the term "register set" to describe one or more
213  * PCI BARs which form a logical address. For example, a 64-bit address uses
214  * two BARs, and thus constitute a register set.
215  *
216  * @param ocs Pointer to the driver's context
217  * @param rset Register Set to use
218  * @param off Offset from the base address of the Register Set
219  * @param val Value to write
220  *
221  * @return none
222  */
223 void
224 ocs_reg_write8(ocs_t *ocs, uint32_t rset, uint32_t off, uint8_t val)
225 {
226 	ocs_pci_reg_t		*reg = NULL;
227 
228 	reg = &ocs->reg[rset];
229 
230 	return bus_space_write_1(reg->btag, reg->bhandle, off, val);
231 }
232 
233 /**
234  * @ingroup os
235  * @brief Allocate host memory
236  *
237  * @param os OS handle
238  * @param size number of bytes to allocate
239  * @param flags additional options
240  *
241  * @return pointer to allocated memory, NULL otherwise
242  */
243 void *
244 ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags)
245 {
246 	if ((flags & OCS_M_NOWAIT) == 0) {
247 		flags |= M_WAITOK;
248 	}
249 
250 #ifndef OCS_DEBUG_MEMORY
251 	return malloc(size, M_OCS, flags);
252 #else
253 	char nameb[80];
254 	long offset = 0;
255 	void *addr = malloc(size, M_OCS, flags);
256 
257 	linker_ddb_search_symbol_name(__builtin_return_address(1), nameb, sizeof(nameb), &offset);
258 	printf("A: %p %ld @ %s+%#lx\n", addr, size, nameb, offset);
259 
260 	return addr;
261 #endif
262 }
263 
264 /**
265  * @ingroup os
266  * @brief Free host memory
267  *
268  * @param os OS handle
269  * @param addr pointer to memory
270  * @param size bytes to free
271  *
272  * @note size ignored in BSD
273  */
274 void
275 ocs_free(ocs_os_handle_t os, void *addr, size_t size)
276 {
277 #ifndef OCS_DEBUG_MEMORY
278 	free(addr, M_OCS);
279 #else
280 	printf("F: %p %ld\n", addr, size);
281 	free(addr, M_OCS);
282 #endif
283 }
284 
285 /**
286  * @brief Callback function provided to bus_dmamap_load
287  *
288  * Function loads the physical / bus address into the DMA descriptor. The caller
289  * can detect a mapping failure if a descriptor's phys element is zero.
290  *
291  * @param arg Argument provided to bus_dmamap_load is a ocs_dma_t
292  * @param seg Array of DMA segment(s), each describing segment's address and length
293  * @param nseg Number of elements in array
294  * @param error Indicates success (0) or failure of mapping
295  */
296 static void
297 ocs_dma_load(void *arg, bus_dma_segment_t *seg, int nseg, int error)
298 {
299 	ocs_dma_t	*dma = arg;
300 
301 	if (error) {
302 		printf("%s: error=%d\n", __func__, error);
303 		dma->phys = 0;
304 	} else {
305 		dma->phys = seg->ds_addr;
306 	}
307 }
308 
309 /**
310  * @ingroup os
311  * @brief Free a DMA capable block of memory
312  *
313  * @param os Device abstraction
314  * @param dma DMA descriptor for memory to be freed
315  *
316  * @return 0 if memory is de-allocated, -1 otherwise
317  */
318 int32_t
319 ocs_dma_free(ocs_os_handle_t os, ocs_dma_t *dma)
320 {
321 	struct ocs_softc	*ocs = os;
322 
323 	if (!dma) {
324 		device_printf(ocs->dev, "%s: bad parameter(s) dma=%p\n", __func__, dma);
325 		return -1;
326 	}
327 
328 	if (dma->size == 0) {
329 		return 0;
330 	}
331 
332 	if (dma->map) {
333 		bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD |
334 				BUS_DMASYNC_POSTWRITE);
335 		bus_dmamap_unload(dma->tag, dma->map);
336 	}
337 
338 	if (dma->virt) {
339 		bus_dmamem_free(dma->tag, dma->virt, dma->map);
340 		bus_dmamap_destroy(dma->tag, dma->map);
341 	}
342 	bus_dma_tag_destroy(dma->tag);
343 
344 	bzero(dma, sizeof(ocs_dma_t));
345 
346 	return 0;
347 }
348 
349 /**
350  * @ingroup os
351  * @brief Allocate a DMA capable block of memory
352  *
353  * @param os Device abstraction
354  * @param dma DMA descriptor containing results of memory allocation
355  * @param size Size in bytes of desired allocation
356  * @param align Alignment in bytes
357  *
358  * @return 0 on success, ENOMEM otherwise
359  */
360 int32_t
361 ocs_dma_alloc(ocs_os_handle_t os, ocs_dma_t *dma, size_t size, size_t align)
362 {
363 	struct ocs_softc	*ocs = os;
364 
365 	if (!dma || !size) {
366 		device_printf(ocs->dev, "%s bad parameter(s) dma=%p size=%zd\n",
367 				__func__, dma, size);
368 		return ENOMEM;
369 	}
370 
371 	bzero(dma, sizeof(ocs_dma_t));
372 
373 	/* create a "tag" that describes the desired memory allocation */
374 	if (bus_dma_tag_create(ocs->dmat, align, 0, BUS_SPACE_MAXADDR,
375 				BUS_SPACE_MAXADDR, NULL, NULL,
376 				size, 1, size, 0, NULL, NULL, &dma->tag)) {
377 		device_printf(ocs->dev, "DMA tag allocation failed\n");
378 		return ENOMEM;
379 	}
380 
381 	dma->size = size;
382 
383 	/* allocate the memory */
384 	if (bus_dmamem_alloc(dma->tag, &dma->virt, BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
385 				&dma->map)) {
386 		device_printf(ocs->dev, "DMA memory allocation failed s=%zd a=%zd\n", size, align);
387 		ocs_dma_free(ocs, dma);
388 		return ENOMEM;
389 	}
390 
391 	dma->alloc = dma->virt;
392 
393 	/* map virtual address to device visible address */
394 	if (bus_dmamap_load(dma->tag, dma->map, dma->virt, dma->size, ocs_dma_load,
395 				dma, 0)) {
396 		device_printf(ocs->dev, "DMA memory load failed\n");
397 		ocs_dma_free(ocs, dma);
398 		return ENOMEM;
399 	}
400 
401 	/* if the DMA map load callback fails, it sets the physical address to zero */
402 	if (0 == dma->phys) {
403 		device_printf(ocs->dev, "ocs_dma_load failed\n");
404 		ocs_dma_free(ocs, dma);
405 		return ENOMEM;
406 	}
407 
408 	return 0;
409 }
410 
411 /**
412  * @ingroup os
413  * @brief Synchronize the DMA buffer memory
414  *
415  * Ensures memory coherency between the CPU and device
416  *
417  * @param dma DMA descriptor of memory to synchronize
418  * @param flags Describes direction of synchronization
419  *   See BUS_DMA(9) for details
420  *   - BUS_DMASYNC_PREWRITE
421  *   - BUS_DMASYNC_POSTREAD
422  */
423 void
424 ocs_dma_sync(ocs_dma_t *dma, uint32_t flags)
425 {
426 	bus_dmamap_sync(dma->tag, dma->map, flags);
427 }
428 
429 int32_t
430 ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
431 {
432 	if (!dma)
433 		return -1;
434 	if (!buffer)
435 		return -1;
436 	if (buffer_length == 0)
437 		return 0;
438 	if (buffer_length > dma->size)
439 		buffer_length = dma->size;
440 	ocs_memcpy(dma->virt, buffer, buffer_length);
441 	dma->len = buffer_length;
442 	return buffer_length;
443 }
444 
445 int32_t
446 ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
447 {
448 	if (!dma)
449 		return -1;
450 	if (!buffer)
451 		return -1;
452 	if (buffer_length == 0)
453 		return 0;
454 	if (buffer_length > dma->len)
455 		buffer_length = dma->len;
456 	ocs_memcpy(buffer, dma->virt, buffer_length);
457 	return buffer_length;
458 }
459 
460 /**
461  * @ingroup os
462  * @brief Initialize a lock
463  *
464  * @param lock lock to initialize
465  * @param name string identifier for the lock
466  */
467 void
468 ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...)
469 {
470 	va_list ap;
471 
472 	va_start(ap, name);
473 	ocs_vsnprintf(lock->name, MAX_LOCK_DESC_LEN, name, ap);
474 	va_end(ap);
475 
476 	mtx_init(&lock->lock, lock->name, NULL, MTX_DEF);
477 }
478 
479 /**
480  * @brief Allocate a bit map
481  *
482  * For BSD, this is a simple character string
483  *
484  * @param n_bits number of bits in bit map
485  *
486  * @return pointer to the bit map, NULL on error
487  */
488 ocs_bitmap_t *
489 ocs_bitmap_alloc(uint32_t n_bits)
490 {
491 
492 	return malloc(bitstr_size(n_bits), M_OCS, M_ZERO | M_NOWAIT);
493 }
494 
495 /**
496  * @brief Free a bit map
497  *
498  * @param bitmap pointer to previously allocated bit map
499  */
500 void
501 ocs_bitmap_free(ocs_bitmap_t *bitmap)
502 {
503 
504 	free(bitmap, M_OCS);
505 }
506 
507 /**
508  * @brief find next unset bit and set it
509  *
510  * @param bitmap bit map to search
511  * @param n_bits number of bits in map
512  *
513  * @return bit position or -1 if map is full
514  */
515 int32_t
516 ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits)
517 {
518 	int32_t		position = -1;
519 
520 	bit_ffc(bitmap, n_bits, &position);
521 
522 	if (-1 != position) {
523 		bit_set(bitmap, position);
524 	}
525 
526 	return position;
527 }
528 
529 /**
530  * @brief search for next (un)set bit
531  *
532  * @param bitmap bit map to search
533  * @param set search for a set or unset bit
534  * @param n_bits number of bits in map
535  *
536  * @return bit position or -1
537  */
538 int32_t
539 ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits)
540 {
541 	int32_t		position;
542 
543 	if (!bitmap) {
544 		return -1;
545 	}
546 
547 	if (set) {
548 		bit_ffs(bitmap, n_bits, &position);
549 	} else {
550 		bit_ffc(bitmap, n_bits, &position);
551 	}
552 
553 	return position;
554 }
555 
556 /**
557  * @brief clear the specified bit
558  *
559  * @param bitmap pointer to bit map
560  * @param bit bit number to clear
561  */
562 void
563 ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit)
564 {
565 	bit_clear(bitmap, bit);
566 }
567 
568 void _ocs_log(ocs_t *ocs, const char *func_name, int line, const char *fmt, ...)
569 {
570 	va_list ap;
571 	char buf[256];
572 	char *p = buf;
573 
574 	va_start(ap, fmt);
575 
576 	/* TODO: Add Current PID info here. */
577 
578 	p += snprintf(p, sizeof(buf) - (p - buf), "%s: ", DRV_NAME);
579 	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", func_name);
580 	p += snprintf(p, sizeof(buf) - (p - buf), "%i:", line);
581 	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", (ocs != NULL) ? device_get_nameunit(ocs->dev) : "");
582 	p += vsnprintf(p, sizeof(buf) - (p - buf), fmt, ap);
583 
584 	va_end(ap);
585 
586 	printf("%s", buf);
587 }
588 
589 /**
590  * @brief Common thread call function
591  *
592  * This is the common function called whenever a thread instantiated by ocs_thread_create() is started.
593  * It captures the return value from the actual thread function and stashes it in the thread object, to
594  * be later retrieved by ocs_thread_get_retval(), and calls kthread_exit(), the proscribed method to terminate
595  * a thread.
596  *
597  * @param arg a pointer to the thread object
598  *
599  * @return none
600  */
601 
602 static void
603 ocs_thread_call_fctn(void *arg)
604 {
605 	ocs_thread_t *thread = arg;
606 	thread->retval = (*thread->fctn)(thread->arg);
607 	ocs_free(NULL, thread->name, ocs_strlen(thread->name+1));
608 	kthread_exit();
609 }
610 
611 /**
612  * @brief Create a kernel thread
613  *
614  * Creates a kernel thread and optionally starts it.   If the thread is not immediately
615  * started, ocs_thread_start() should be called at some later point.
616  *
617  * @param os OS handle
618  * @param thread pointer to thread object
619  * @param fctn function for thread to be begin executing
620  * @param name text name to identify thread
621  * @param arg application specific argument passed to thread function
622  * @param start start option, OCS_THREAD_RUN will start the thread immediately,
623  *			OCS_THREAD_CREATE will create but not start the thread
624  *
625  * @return returns 0 for success, a negative error code value for failure.
626  */
627 
628 int32_t
629 ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn, const char *name, void *arg, ocs_thread_start_e start)
630 {
631 	int32_t rc = 0;
632 
633 	ocs_memset(thread, 0, sizeof(*thread));
634 
635 	thread->fctn = fctn;
636 	thread->name = ocs_strdup(name);
637 	if (thread->name == NULL) {
638 		thread->name = "unknown";
639 	}
640 	thread->arg = arg;
641 
642 	ocs_atomic_set(&thread->terminate, 0);
643 
644 	rc = kthread_add(ocs_thread_call_fctn, thread, NULL, &thread->tcb, (start == OCS_THREAD_CREATE) ? RFSTOPPED : 0,
645 		OCS_THREAD_DEFAULT_STACK_SIZE_PAGES, "%s", name);
646 
647 	return rc;
648 }
649 
650 /**
651  * @brief Start a thread
652  *
653  * Starts a thread that was created with OCS_THREAD_CREATE rather than OCS_THREAD_RUN
654  *
655  * @param thread pointer to thread object
656  *
657  * @return returns 0 for success, a negative error code value for failure.
658  */
659 
660 int32_t ocs_thread_start(ocs_thread_t *thread)
661 {
662 
663 	thread_lock(thread->tcb);
664 	sched_add(thread->tcb, SRQ_BORING);
665 	return 0;
666 }
667 
668 /**
669  * @brief return thread argument
670  *
671  * Returns a pointer to the thread's application specific argument
672  *
673  * @param mythread pointer to the thread object
674  *
675  * @return pointer to application specific argument
676  */
677 
678 void *ocs_thread_get_arg(ocs_thread_t *mythread)
679 {
680 	return mythread->arg;
681 }
682 
683 /**
684  * @brief Request thread stop
685  *
686  * A stop request is made to the thread.  This is a voluntary call, the thread needs
687  * to periodically query its terminate request using ocs_thread_terminate_requested()
688  *
689  * @param thread pointer to thread object
690  *
691  * @return returns 0 for success, a negative error code value for failure.
692  */
693 
694 int32_t
695 ocs_thread_terminate(ocs_thread_t *thread)
696 {
697 	ocs_atomic_set(&thread->terminate, 1);
698 	return 0;
699 }
700 
701 /**
702  * @brief See if a terminate request has been made
703  *
704  * Check to see if a stop request has been made to the current thread.  This
705  * function would be used by a thread to see if it should terminate.
706  *
707  * @return returns non-zero if a stop has been requested
708  */
709 
710 int32_t ocs_thread_terminate_requested(ocs_thread_t *thread)
711 {
712 	return ocs_atomic_read(&thread->terminate);
713 }
714 
715 /**
716  * @brief Retrieve threads return value
717  *
718  * After a thread has terminated, it's return value may be retrieved with this function.
719  *
720  * @param thread pointer to thread object
721  *
722  * @return return value from thread function
723  */
724 
725 int32_t
726 ocs_thread_get_retval(ocs_thread_t *thread)
727 {
728 	return thread->retval;
729 }
730 
731 /**
732  * @brief Request that the currently running thread yield
733  *
734  * The currently running thread yields to the scheduler
735  *
736  * @param thread pointer to thread (ignored)
737  *
738  * @return none
739  */
740 
741 void
742 ocs_thread_yield(ocs_thread_t *thread) {
743 	pause("thread yield", 1);
744 }
745 
746 ocs_thread_t *
747 ocs_thread_self(void)
748 {
749 	ocs_printf(">>> %s not implemented\n", __func__);
750 	ocs_abort();
751 }
752 
753 int32_t
754 ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu)
755 {
756 	ocs_printf(">>> %s not implemented\n", __func__);
757 	return -1;
758 }
759 
760 int32_t
761 ocs_thread_getcpu(void)
762 {
763 	return curcpu;
764 }
765 
766 int
767 ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...)
768 {
769 	va_list ap;
770 
771 	va_start(ap, name);
772 	ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap);
773 	va_end(ap);
774 
775 	sema_init(&sem->sem, val, sem->name);
776 	return 0;
777 }
778 
779 /**
780  * @ingroup os
781  * @brief  Copy user arguments in to kernel space for an ioctl
782  * @par Description
783  * This function is called at the beginning of an ioctl function
784  * to copy the ioctl argument from user space to kernel space.
785  *
786  * BSD handles this for us - arg is already in kernel space,
787  * so we just return it.
788  *
789  * @param os OS handle
790  * @param arg The argument passed to the ioctl function
791  * @param size The size of the structure pointed to by arg
792  *
793  * @return A pointer to a kernel space copy of the argument on
794  *	success; NULL on failure
795  */
796 void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size)
797 {
798 	 return arg;
799 }
800 
801 /**
802  * @ingroup os
803  * @brief  Copy results of an ioctl back to user space
804  * @par Description
805  * This function is called at the end of ioctl processing to
806  * copy the argument back to user space.
807  *
808  * BSD handles this for us.
809  *
810  * @param os OS handle
811  * @param arg The argument passed to the ioctl function
812  * @param kern_ptr A pointer to the kernel space copy of the
813  *		   argument
814  * @param size The size of the structure pointed to by arg.
815  *
816  * @return Returns 0.
817  */
818 int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size)
819 {
820 	return 0;
821 }
822 
823 /**
824  * @ingroup os
825  * @brief  Free memory allocated by ocs_ioctl_preprocess
826  * @par Description
827  * This function is called in the event of an error in ioctl
828  * processing.  For operating environments where ocs_ioctlpreprocess
829  * allocates memory, this call frees the memory without copying
830  * results back to user space.
831  *
832  * For BSD, because no memory was allocated in ocs_ioctl_preprocess,
833  * nothing needs to be done here.
834  *
835  * @param os OS handle
836  * @param kern_ptr A pointer to the kernel space copy of the
837  *		   argument
838  * @param size The size of the structure pointed to by arg.
839  *
840  * @return Returns nothing.
841  */
842 void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size)
843 {
844 	return;
845 }
846 
847 void ocs_intr_disable(ocs_os_handle_t os)
848 {
849 }
850 
851 void ocs_intr_enable(ocs_os_handle_t os)
852 {
853 }
854 
855 void ocs_print_stack(void)
856 {
857 #if defined(STACK)
858 	struct stack st;
859 
860 	stack_zero(&st);
861 	stack_save(&st);
862 	stack_print(&st);
863 #endif
864 }
865 
866 void ocs_abort(void)
867 {
868 	panic(">>> abort/panic\n");
869 }
870 
871 const char *
872 ocs_pci_model(uint16_t vendor, uint16_t device)
873 {
874 	switch (device) {
875 	case PCI_PRODUCT_EMULEX_OCE16002:	return "OCE16002";
876 	case PCI_PRODUCT_EMULEX_OCE1600_VF:	return "OCE1600_VF";
877 	case PCI_PRODUCT_EMULEX_OCE50102:	return "OCE50102";
878 	case PCI_PRODUCT_EMULEX_OCE50102_VF:	return "OCE50102_VR";
879 	default:
880 		break;
881 	}
882 
883 	return "unknown";
884 }
885 
886 void
887 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
888 {
889 	*bus = pci_get_bus(ocs->dev);
890 	*dev = pci_get_slot(ocs->dev);
891 	*func= pci_get_function(ocs->dev);
892 }
893 
894 /**
895  * @brief return CPU information
896  *
897  * This function populates the ocs_cpuinfo_t buffer with CPU information
898  *
899  * @param cpuinfo pointer to ocs_cpuinfo_t buffer
900  *
901  * @return returns 0 for success, a negative error code value for failure.
902  */
903 extern int mp_ncpus;
904 int32_t
905 ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo)
906 {
907 	cpuinfo->num_cpus = mp_ncpus;
908 	return 0;
909 }
910 
911 uint32_t
912 ocs_get_num_cpus(void)
913 {
914 	static ocs_cpuinfo_t cpuinfo;
915 
916 	if (cpuinfo.num_cpus == 0) {
917 		ocs_get_cpuinfo(&cpuinfo);
918 	}
919 	return cpuinfo.num_cpus;
920 }
921 
922 void
923 __ocs_callout(void *t)
924 {
925 	ocs_timer_t *timer = t;
926 
927 	if (callout_pending(&timer->callout)) {
928 		/* Callout was reset */
929 		return;
930 	}
931 
932 	if (!callout_active(&timer->callout)) {
933 		/* Callout was stopped */
934 		return;
935 	}
936 
937 	callout_deactivate(&timer->callout);
938 
939 	if (timer->func) {
940 		timer->func(timer->data);
941 	}
942 }
943 
944 int32_t
945 ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms)
946 {
947 	struct	timeval tv;
948 	int	hz;
949 
950 	if (timer == NULL) {
951 		ocs_log_err(NULL, "bad parameter\n");
952 		return -1;
953 	}
954 
955 	if (!mtx_initialized(&timer->lock)) {
956 		mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF);
957 	}
958 
959 	callout_init_mtx(&timer->callout, &timer->lock, 0);
960 
961 	timer->func = func;
962 	timer->data = data;
963 
964 	tv.tv_sec  = timeout_ms / 1000;
965 	tv.tv_usec = (timeout_ms % 1000) * 1000;
966 
967 	hz = tvtohz(&tv);
968 	if (hz < 0)
969 		hz = INT32_MAX;
970 	if (hz == 0)
971 		hz = 1;
972 
973 	mtx_lock(&timer->lock);
974 		callout_reset(&timer->callout, hz, __ocs_callout, timer);
975 	mtx_unlock(&timer->lock);
976 
977 	return 0;
978 }
979 
980 int32_t
981 ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms)
982 {
983 	struct	timeval tv;
984 	int	hz;
985 
986 	if (timer == NULL) {
987 		ocs_log_err(NULL, "bad parameter\n");
988 		return -1;
989 	}
990 
991 	tv.tv_sec  = timeout_ms / 1000;
992 	tv.tv_usec = (timeout_ms % 1000) * 1000;
993 
994 	hz = tvtohz(&tv);
995 	if (hz < 0)
996 		hz = INT32_MAX;
997 	if (hz == 0)
998 		hz = 1;
999 
1000 	mtx_lock(&timer->lock);
1001 		callout_reset(&timer->callout, hz, __ocs_callout, timer);
1002 	mtx_unlock(&timer->lock);
1003 
1004 	return 0;
1005 }
1006 
1007 int32_t
1008 ocs_timer_pending(ocs_timer_t *timer)
1009 {
1010 	return callout_active(&timer->callout);
1011 }
1012 
1013 int32_t
1014 ocs_del_timer(ocs_timer_t *timer)
1015 {
1016 
1017 	mtx_lock(&timer->lock);
1018 		callout_stop(&timer->callout);
1019 	mtx_unlock(&timer->lock);
1020 
1021 	return 0;
1022 }
1023 
1024 char *
1025 ocs_strdup(const char *s)
1026 {
1027 	uint32_t l = strlen(s);
1028 	char *d;
1029 
1030 	d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT);
1031 	if (d != NULL) {
1032 		ocs_strcpy(d, s);
1033 	}
1034 	return d;
1035 }
1036 
1037 void
1038 _ocs_assert(const char *cond, const char *filename, int linenum)
1039 {
1040 	const char *fn = strrchr(__FILE__, '/');
1041 
1042 	ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond);
1043 	ocs_print_stack();
1044 	ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE);
1045 }
1046