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
41static 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
48callout_func_t	__ocs_callout;
49
50uint32_t
51ocs_config_read32(ocs_os_handle_t os, uint32_t reg)
52{
53	return pci_read_config(os->dev, reg, 4);
54}
55
56uint16_t
57ocs_config_read16(ocs_os_handle_t os, uint32_t reg)
58{
59	return pci_read_config(os->dev, reg, 2);
60}
61
62uint8_t
63ocs_config_read8(ocs_os_handle_t os, uint32_t reg)
64{
65	return pci_read_config(os->dev, reg, 1);
66}
67
68void
69ocs_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
74void
75ocs_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
80void
81ocs_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 */
100uint32_t
101ocs_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 */
124uint16_t
125ocs_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 */
148uint8_t
149ocs_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 */
173void
174ocs_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 */
198void
199ocs_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 */
223void
224ocs_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 */
243void *
244ocs_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 */
274void
275ocs_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 */
296static void
297ocs_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 */
318int32_t
319ocs_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 */
360int32_t
361ocs_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 */
423void
424ocs_dma_sync(ocs_dma_t *dma, uint32_t flags)
425{
426	bus_dmamap_sync(dma->tag, dma->map, flags);
427}
428
429int32_t
430ocs_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
445int32_t
446ocs_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 */
467void
468ocs_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 */
488ocs_bitmap_t *
489ocs_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 */
500void
501ocs_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 */
515int32_t
516ocs_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 */
538int32_t
539ocs_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 */
562void
563ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit)
564{
565	bit_clear(bitmap, bit);
566}
567
568void _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
602static void
603ocs_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
628int32_t
629ocs_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
660int32_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
678void *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
694int32_t
695ocs_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
710int32_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
725int32_t
726ocs_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
741void
742ocs_thread_yield(ocs_thread_t *thread) {
743	pause("thread yield", 1);
744}
745
746ocs_thread_t *
747ocs_thread_self(void)
748{
749	ocs_printf(">>> %s not implemented\n", __func__);
750	ocs_abort();
751}
752
753int32_t
754ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu)
755{
756	ocs_printf(">>> %s not implemented\n", __func__);
757	return -1;
758}
759
760int32_t
761ocs_thread_getcpu(void)
762{
763	return curcpu;
764}
765
766int
767ocs_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 */
796void *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 */
818int32_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 */
842void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size)
843{
844	return;
845}
846
847void ocs_intr_disable(ocs_os_handle_t os)
848{
849}
850
851void ocs_intr_enable(ocs_os_handle_t os)
852{
853}
854
855void 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
866void ocs_abort(void)
867{
868	panic(">>> abort/panic\n");
869}
870
871const char *
872ocs_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
886int32_t
887ocs_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	return 0;
893}
894
895/**
896 * @brief return CPU information
897 *
898 * This function populates the ocs_cpuinfo_t buffer with CPU information
899 *
900 * @param cpuinfo pointer to ocs_cpuinfo_t buffer
901 *
902 * @return returns 0 for success, a negative error code value for failure.
903 */
904extern int mp_ncpus;
905int32_t
906ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo)
907{
908	cpuinfo->num_cpus = mp_ncpus;
909	return 0;
910}
911
912uint32_t
913ocs_get_num_cpus(void)
914{
915	static ocs_cpuinfo_t cpuinfo;
916
917	if (cpuinfo.num_cpus == 0) {
918		ocs_get_cpuinfo(&cpuinfo);
919	}
920	return cpuinfo.num_cpus;
921}
922
923void
924__ocs_callout(void *t)
925{
926	ocs_timer_t *timer = t;
927
928	if (callout_pending(&timer->callout)) {
929		/* Callout was reset */
930		return;
931	}
932
933	if (!callout_active(&timer->callout)) {
934		/* Callout was stopped */
935		return;
936	}
937
938	callout_deactivate(&timer->callout);
939
940	if (timer->func) {
941		timer->func(timer->data);
942	}
943}
944
945int32_t
946ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms)
947{
948	struct	timeval tv;
949	int	hz;
950
951	if (timer == NULL) {
952		ocs_log_err(NULL, "bad parameter\n");
953		return -1;
954	}
955
956	if (!mtx_initialized(&timer->lock)) {
957		mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF);
958	}
959
960	callout_init_mtx(&timer->callout, &timer->lock, 0);
961
962	timer->func = func;
963	timer->data = data;
964
965	tv.tv_sec  = timeout_ms / 1000;
966	tv.tv_usec = (timeout_ms % 1000) * 1000;
967
968	hz = tvtohz(&tv);
969	if (hz < 0)
970		hz = INT32_MAX;
971	if (hz == 0)
972		hz = 1;
973
974	mtx_lock(&timer->lock);
975		callout_reset(&timer->callout, hz, __ocs_callout, timer);
976	mtx_unlock(&timer->lock);
977
978	return 0;
979}
980
981int32_t
982ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms)
983{
984	struct	timeval tv;
985	int	hz;
986
987	if (timer == NULL) {
988		ocs_log_err(NULL, "bad parameter\n");
989		return -1;
990	}
991
992	tv.tv_sec  = timeout_ms / 1000;
993	tv.tv_usec = (timeout_ms % 1000) * 1000;
994
995	hz = tvtohz(&tv);
996	if (hz < 0)
997		hz = INT32_MAX;
998	if (hz == 0)
999		hz = 1;
1000
1001	mtx_lock(&timer->lock);
1002		callout_reset(&timer->callout, hz, __ocs_callout, timer);
1003	mtx_unlock(&timer->lock);
1004
1005	return 0;
1006}
1007
1008int32_t
1009ocs_timer_pending(ocs_timer_t *timer)
1010{
1011	return callout_active(&timer->callout);
1012}
1013
1014int32_t
1015ocs_del_timer(ocs_timer_t *timer)
1016{
1017
1018	mtx_lock(&timer->lock);
1019		callout_stop(&timer->callout);
1020	mtx_unlock(&timer->lock);
1021
1022	return 0;
1023}
1024
1025char *
1026ocs_strdup(const char *s)
1027{
1028	uint32_t l = strlen(s);
1029	char *d;
1030
1031	d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT);
1032	if (d != NULL) {
1033		ocs_strcpy(d, s);
1034	}
1035	return d;
1036}
1037
1038void
1039_ocs_assert(const char *cond, const char *filename, int linenum)
1040{
1041	const char *fn = strrchr(__FILE__, '/');
1042
1043	ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond);
1044	ocs_print_stack();
1045	ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE);
1046}
1047