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