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