xref: /freebsd/sys/dev/ocs_fc/ocs_os.c (revision 95ee2897)
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 
39 static 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 
46 callout_func_t	__ocs_callout;
47 
48 uint32_t
ocs_config_read32(ocs_os_handle_t os,uint32_t reg)49 ocs_config_read32(ocs_os_handle_t os, uint32_t reg)
50 {
51 	return pci_read_config(os->dev, reg, 4);
52 }
53 
54 uint16_t
ocs_config_read16(ocs_os_handle_t os,uint32_t reg)55 ocs_config_read16(ocs_os_handle_t os, uint32_t reg)
56 {
57 	return pci_read_config(os->dev, reg, 2);
58 }
59 
60 uint8_t
ocs_config_read8(ocs_os_handle_t os,uint32_t reg)61 ocs_config_read8(ocs_os_handle_t os, uint32_t reg)
62 {
63 	return pci_read_config(os->dev, reg, 1);
64 }
65 
66 void
ocs_config_write8(ocs_os_handle_t os,uint32_t reg,uint8_t val)67 ocs_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 
72 void
ocs_config_write16(ocs_os_handle_t os,uint32_t reg,uint16_t val)73 ocs_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 
78 void
ocs_config_write32(ocs_os_handle_t os,uint32_t reg,uint32_t val)79 ocs_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  */
98 uint32_t
ocs_reg_read32(ocs_t * ocs,uint32_t rset,uint32_t off)99 ocs_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  */
122 uint16_t
ocs_reg_read16(ocs_t * ocs,uint32_t rset,uint32_t off)123 ocs_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  */
146 uint8_t
ocs_reg_read8(ocs_t * ocs,uint32_t rset,uint32_t off)147 ocs_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  */
171 void
ocs_reg_write32(ocs_t * ocs,uint32_t rset,uint32_t off,uint32_t val)172 ocs_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  */
196 void
ocs_reg_write16(ocs_t * ocs,uint32_t rset,uint32_t off,uint16_t val)197 ocs_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  */
221 void
ocs_reg_write8(ocs_t * ocs,uint32_t rset,uint32_t off,uint8_t val)222 ocs_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  */
241 void *
ocs_malloc(ocs_os_handle_t os,size_t size,int32_t flags)242 ocs_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  */
272 void
ocs_free(ocs_os_handle_t os,void * addr,size_t size)273 ocs_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  */
294 static void
ocs_dma_load(void * arg,bus_dma_segment_t * seg,int nseg,int error)295 ocs_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  */
316 int32_t
ocs_dma_free(ocs_os_handle_t os,ocs_dma_t * dma)317 ocs_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  */
358 int32_t
ocs_dma_alloc(ocs_os_handle_t os,ocs_dma_t * dma,size_t size,size_t align)359 ocs_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  */
421 void
ocs_dma_sync(ocs_dma_t * dma,uint32_t flags)422 ocs_dma_sync(ocs_dma_t *dma, uint32_t flags)
423 {
424 	bus_dmamap_sync(dma->tag, dma->map, flags);
425 }
426 
427 int32_t
ocs_dma_copy_in(ocs_dma_t * dma,void * buffer,uint32_t buffer_length)428 ocs_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 
443 int32_t
ocs_dma_copy_out(ocs_dma_t * dma,void * buffer,uint32_t buffer_length)444 ocs_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  */
465 void
ocs_lock_init(void * os,ocs_lock_t * lock,const char * name,...)466 ocs_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  */
486 ocs_bitmap_t *
ocs_bitmap_alloc(uint32_t n_bits)487 ocs_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  */
498 void
ocs_bitmap_free(ocs_bitmap_t * bitmap)499 ocs_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  */
513 int32_t
ocs_bitmap_find(ocs_bitmap_t * bitmap,uint32_t n_bits)514 ocs_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  */
536 int32_t
ocs_bitmap_search(ocs_bitmap_t * bitmap,uint8_t set,uint32_t n_bits)537 ocs_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  */
560 void
ocs_bitmap_clear(ocs_bitmap_t * bitmap,uint32_t bit)561 ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit)
562 {
563 	bit_clear(bitmap, bit);
564 }
565 
_ocs_log(ocs_t * ocs,const char * func_name,int line,const char * fmt,...)566 void _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 
600 static void
ocs_thread_call_fctn(void * arg)601 ocs_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 
626 int32_t
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)627 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)
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 
ocs_thread_start(ocs_thread_t * thread)658 int32_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 
ocs_thread_get_arg(ocs_thread_t * mythread)676 void *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 
692 int32_t
ocs_thread_terminate(ocs_thread_t * thread)693 ocs_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 
ocs_thread_terminate_requested(ocs_thread_t * thread)708 int32_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 
723 int32_t
ocs_thread_get_retval(ocs_thread_t * thread)724 ocs_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 
739 void
ocs_thread_yield(ocs_thread_t * thread)740 ocs_thread_yield(ocs_thread_t *thread) {
741 	pause("thread yield", 1);
742 }
743 
744 ocs_thread_t *
ocs_thread_self(void)745 ocs_thread_self(void)
746 {
747 	ocs_printf(">>> %s not implemented\n", __func__);
748 	ocs_abort();
749 }
750 
751 int32_t
ocs_thread_setcpu(ocs_thread_t * thread,uint32_t cpu)752 ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu)
753 {
754 	ocs_printf(">>> %s not implemented\n", __func__);
755 	return -1;
756 }
757 
758 int32_t
ocs_thread_getcpu(void)759 ocs_thread_getcpu(void)
760 {
761 	return curcpu;
762 }
763 
764 int
ocs_sem_init(ocs_sem_t * sem,int val,const char * name,...)765 ocs_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  */
ocs_ioctl_preprocess(ocs_os_handle_t os,void * arg,size_t size)794 void *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  */
ocs_ioctl_postprocess(ocs_os_handle_t os,void * arg,void * kern_ptr,size_t size)816 int32_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  */
ocs_ioctl_free(ocs_os_handle_t os,void * kern_ptr,size_t size)840 void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size)
841 {
842 	return;
843 }
844 
ocs_intr_disable(ocs_os_handle_t os)845 void ocs_intr_disable(ocs_os_handle_t os)
846 {
847 }
848 
ocs_intr_enable(ocs_os_handle_t os)849 void ocs_intr_enable(ocs_os_handle_t os)
850 {
851 }
852 
ocs_print_stack(void)853 void 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 
ocs_abort(void)863 void ocs_abort(void)
864 {
865 	panic(">>> abort/panic\n");
866 }
867 
868 const char *
ocs_pci_model(uint16_t vendor,uint16_t device)869 ocs_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 
883 void
ocs_get_bus_dev_func(ocs_t * ocs,uint8_t * bus,uint8_t * dev,uint8_t * func)884 ocs_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  */
900 extern int mp_ncpus;
901 int32_t
ocs_get_cpuinfo(ocs_cpuinfo_t * cpuinfo)902 ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo)
903 {
904 	cpuinfo->num_cpus = mp_ncpus;
905 	return 0;
906 }
907 
908 uint32_t
ocs_get_num_cpus(void)909 ocs_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 
919 void
__ocs_callout(void * t)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 
941 int32_t
ocs_setup_timer(ocs_os_handle_t os,ocs_timer_t * timer,void (* func)(void * arg),void * data,uint32_t timeout_ms)942 ocs_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 
977 int32_t
ocs_mod_timer(ocs_timer_t * timer,uint32_t timeout_ms)978 ocs_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 
1004 int32_t
ocs_timer_pending(ocs_timer_t * timer)1005 ocs_timer_pending(ocs_timer_t *timer)
1006 {
1007 	return callout_active(&timer->callout);
1008 }
1009 
1010 int32_t
ocs_del_timer(ocs_timer_t * timer)1011 ocs_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 
1021 char *
ocs_strdup(const char * s)1022 ocs_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 
1034 void
_ocs_assert(const char * cond,const char * filename,int linenum)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