1331766Sken/*-
2331766Sken * Copyright (c) 2017 Broadcom. All rights reserved.
3331766Sken * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4331766Sken *
5331766Sken * Redistribution and use in source and binary forms, with or without
6331766Sken * modification, are permitted provided that the following conditions are met:
7331766Sken *
8331766Sken * 1. Redistributions of source code must retain the above copyright notice,
9331766Sken *    this list of conditions and the following disclaimer.
10331766Sken *
11331766Sken * 2. Redistributions in binary form must reproduce the above copyright notice,
12331766Sken *    this list of conditions and the following disclaimer in the documentation
13331766Sken *    and/or other materials provided with the distribution.
14331766Sken *
15331766Sken * 3. Neither the name of the copyright holder nor the names of its contributors
16331766Sken *    may be used to endorse or promote products derived from this software
17331766Sken *    without specific prior written permission.
18331766Sken *
19331766Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20331766Sken * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21331766Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22331766Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23331766Sken * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24331766Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25331766Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26331766Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27331766Sken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28331766Sken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29331766Sken * POSSIBILITY OF SUCH DAMAGE.
30331766Sken *
31331766Sken * $FreeBSD: stable/11/sys/dev/ocs_fc/ocs_os.c 333991 2018-05-21 18:59:34Z ken $
32331766Sken */
33331766Sken
34331766Sken/**
35331766Sken * @file
36331766Sken * Implementation of common BSD OS abstraction functions
37331766Sken */
38331766Sken
39331766Sken#include "ocs.h"
40331766Sken
41331766Skenstatic MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
42331766Sken
43331766Sken#include <dev/pci/pcireg.h>
44331766Sken#include <dev/pci/pcivar.h>
45331766Sken
46331766Sken#include <machine/bus.h>
47331766Sken
48331766Skentimeout_t	__ocs_callout;
49331766Sken
50331766Skenuint32_t
51331766Skenocs_config_read32(ocs_os_handle_t os, uint32_t reg)
52331766Sken{
53331766Sken	return pci_read_config(os->dev, reg, 4);
54331766Sken}
55331766Sken
56331766Skenuint16_t
57331766Skenocs_config_read16(ocs_os_handle_t os, uint32_t reg)
58331766Sken{
59331766Sken	return pci_read_config(os->dev, reg, 2);
60331766Sken}
61331766Sken
62331766Skenuint8_t
63331766Skenocs_config_read8(ocs_os_handle_t os, uint32_t reg)
64331766Sken{
65331766Sken	return pci_read_config(os->dev, reg, 1);
66331766Sken}
67331766Sken
68331766Skenvoid
69331766Skenocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val)
70331766Sken{
71331766Sken	return pci_write_config(os->dev, reg, val, 1);
72331766Sken}
73331766Sken
74331766Skenvoid
75331766Skenocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val)
76331766Sken{
77331766Sken	return pci_write_config(os->dev, reg, val, 2);
78331766Sken}
79331766Sken
80331766Skenvoid
81331766Skenocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val)
82331766Sken{
83331766Sken	return pci_write_config(os->dev, reg, val, 4);
84331766Sken}
85331766Sken
86331766Sken/**
87331766Sken * @ingroup os
88331766Sken * @brief Read a 32bit PCI register
89331766Sken *
90331766Sken * The SLI documentation uses the term "register set" to describe one or more
91331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
92331766Sken * two BARs, and thus constitute a register set.
93331766Sken *
94331766Sken * @param ocs Pointer to the driver's context
95331766Sken * @param rset Register Set to use
96331766Sken * @param off Offset from the base address of the Register Set
97331766Sken *
98331766Sken * @return register value
99331766Sken */
100331766Skenuint32_t
101331766Skenocs_reg_read32(ocs_t *ocs, uint32_t rset, uint32_t off)
102331766Sken{
103331766Sken	ocs_pci_reg_t		*reg = NULL;
104331766Sken
105331766Sken	reg = &ocs->reg[rset];
106331766Sken
107331766Sken	return bus_space_read_4(reg->btag, reg->bhandle, off);
108331766Sken}
109331766Sken
110331766Sken/**
111331766Sken * @ingroup os
112331766Sken * @brief Read a 16bit PCI register
113331766Sken *
114331766Sken * The SLI documentation uses the term "register set" to describe one or more
115331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
116331766Sken * two BARs, and thus constitute a register set.
117331766Sken *
118331766Sken * @param ocs Pointer to the driver's context
119331766Sken * @param rset Register Set to use
120331766Sken * @param off Offset from the base address of the Register Set
121331766Sken *
122331766Sken * @return register value
123331766Sken */
124331766Skenuint16_t
125331766Skenocs_reg_read16(ocs_t *ocs, uint32_t rset, uint32_t off)
126331766Sken{
127331766Sken	ocs_pci_reg_t		*reg = NULL;
128331766Sken
129331766Sken	reg = &ocs->reg[rset];
130331766Sken
131331766Sken	return bus_space_read_2(reg->btag, reg->bhandle, off);
132331766Sken}
133331766Sken
134331766Sken/**
135331766Sken * @ingroup os
136331766Sken * @brief Read a 8bit PCI register
137331766Sken *
138331766Sken * The SLI documentation uses the term "register set" to describe one or more
139331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
140331766Sken * two BARs, and thus constitute a register set.
141331766Sken *
142331766Sken * @param ocs Pointer to the driver's context
143331766Sken * @param rset Register Set to use
144331766Sken * @param off Offset from the base address of the Register Set
145331766Sken *
146331766Sken * @return register value
147331766Sken */
148331766Skenuint8_t
149331766Skenocs_reg_read8(ocs_t *ocs, uint32_t rset, uint32_t off)
150331766Sken{
151331766Sken	ocs_pci_reg_t		*reg = NULL;
152331766Sken
153331766Sken	reg = &ocs->reg[rset];
154331766Sken
155331766Sken	return bus_space_read_1(reg->btag, reg->bhandle, off);
156331766Sken}
157331766Sken
158331766Sken/**
159331766Sken * @ingroup os
160331766Sken * @brief Write a 32bit PCI register
161331766Sken *
162331766Sken * The SLI documentation uses the term "register set" to describe one or more
163331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
164331766Sken * two BARs, and thus constitute a register set.
165331766Sken *
166331766Sken * @param ocs Pointer to the driver's context
167331766Sken * @param rset Register Set to use
168331766Sken * @param off Offset from the base address of the Register Set
169331766Sken * @param val Value to write
170331766Sken *
171331766Sken * @return none
172331766Sken */
173331766Skenvoid
174331766Skenocs_reg_write32(ocs_t *ocs, uint32_t rset, uint32_t off, uint32_t val)
175331766Sken{
176331766Sken	ocs_pci_reg_t		*reg = NULL;
177331766Sken
178331766Sken	reg = &ocs->reg[rset];
179331766Sken
180331766Sken	return bus_space_write_4(reg->btag, reg->bhandle, off, val);
181331766Sken}
182331766Sken
183331766Sken/**
184331766Sken * @ingroup os
185331766Sken * @brief Write a 16-bit PCI register
186331766Sken *
187331766Sken * The SLI documentation uses the term "register set" to describe one or more
188331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
189331766Sken * two BARs, and thus constitute a register set.
190331766Sken *
191331766Sken * @param ocs Pointer to the driver's context
192331766Sken * @param rset Register Set to use
193331766Sken * @param off Offset from the base address of the Register Set
194331766Sken * @param val Value to write
195331766Sken *
196331766Sken * @return none
197331766Sken */
198331766Skenvoid
199331766Skenocs_reg_write16(ocs_t *ocs, uint32_t rset, uint32_t off, uint16_t val)
200331766Sken{
201331766Sken	ocs_pci_reg_t		*reg = NULL;
202331766Sken
203331766Sken	reg = &ocs->reg[rset];
204331766Sken
205331766Sken	return bus_space_write_2(reg->btag, reg->bhandle, off, val);
206331766Sken}
207331766Sken
208331766Sken/**
209331766Sken * @ingroup os
210331766Sken * @brief Write a 8-bit PCI register
211331766Sken *
212331766Sken * The SLI documentation uses the term "register set" to describe one or more
213331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses
214331766Sken * two BARs, and thus constitute a register set.
215331766Sken *
216331766Sken * @param ocs Pointer to the driver's context
217331766Sken * @param rset Register Set to use
218331766Sken * @param off Offset from the base address of the Register Set
219331766Sken * @param val Value to write
220331766Sken *
221331766Sken * @return none
222331766Sken */
223331766Skenvoid
224331766Skenocs_reg_write8(ocs_t *ocs, uint32_t rset, uint32_t off, uint8_t val)
225331766Sken{
226331766Sken	ocs_pci_reg_t		*reg = NULL;
227331766Sken
228331766Sken	reg = &ocs->reg[rset];
229331766Sken
230331766Sken	return bus_space_write_1(reg->btag, reg->bhandle, off, val);
231331766Sken}
232331766Sken
233331766Sken/**
234331766Sken * @ingroup os
235331766Sken * @brief Allocate host memory
236331766Sken *
237331766Sken * @param os OS handle
238331766Sken * @param size number of bytes to allocate
239331766Sken * @param flags additional options
240331766Sken *
241331766Sken * @return pointer to allocated memory, NULL otherwise
242331766Sken */
243331766Skenvoid *
244331766Skenocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags)
245331766Sken{
246331766Sken	if ((flags & OCS_M_NOWAIT) == 0) {
247331766Sken		flags |= M_WAITOK;
248331766Sken	}
249331766Sken
250331766Sken#ifndef OCS_DEBUG_MEMORY
251331766Sken	return malloc(size, M_OCS, flags);
252331766Sken#else
253331766Sken	char nameb[80];
254331766Sken	long offset = 0;
255331766Sken	void *addr = malloc(size, M_OCS, flags);
256331766Sken
257331766Sken	linker_ddb_search_symbol_name(__builtin_return_address(1), nameb, sizeof(nameb), &offset);
258331766Sken	printf("A: %p %ld @ %s+%#lx\n", addr, size, nameb, offset);
259331766Sken
260331766Sken	return addr;
261331766Sken#endif
262331766Sken}
263331766Sken
264331766Sken/**
265331766Sken * @ingroup os
266331766Sken * @brief Free host memory
267331766Sken *
268331766Sken * @param os OS handle
269331766Sken * @param addr pointer to memory
270331766Sken * @param size bytes to free
271331766Sken *
272331766Sken * @note size ignored in BSD
273331766Sken */
274331766Skenvoid
275331766Skenocs_free(ocs_os_handle_t os, void *addr, size_t size)
276331766Sken{
277331766Sken#ifndef OCS_DEBUG_MEMORY
278331766Sken	free(addr, M_OCS);
279331766Sken#else
280331766Sken	printf("F: %p %ld\n", addr, size);
281331766Sken	free(addr, M_OCS);
282331766Sken#endif
283331766Sken}
284331766Sken
285331766Sken/**
286331766Sken * @brief Callback function provided to bus_dmamap_load
287331766Sken *
288331766Sken * Function loads the physical / bus address into the DMA descriptor. The caller
289331766Sken * can detect a mapping failure if a descriptor's phys element is zero.
290331766Sken *
291331766Sken * @param arg Argument provided to bus_dmamap_load is a ocs_dma_t
292331766Sken * @param seg Array of DMA segment(s), each describing segment's address and length
293331766Sken * @param nseg Number of elements in array
294331766Sken * @param error Indicates success (0) or failure of mapping
295331766Sken */
296331766Skenstatic void
297331766Skenocs_dma_load(void *arg, bus_dma_segment_t *seg, int nseg, int error)
298331766Sken{
299331766Sken	ocs_dma_t	*dma = arg;
300331766Sken
301331766Sken	if (error) {
302331766Sken		printf("%s: error=%d\n", __func__, error);
303331766Sken		dma->phys = 0;
304331766Sken	} else {
305331766Sken		dma->phys = seg->ds_addr;
306331766Sken	}
307331766Sken}
308331766Sken
309331766Sken/**
310331766Sken * @ingroup os
311331766Sken * @brief Free a DMA capable block of memory
312331766Sken *
313331766Sken * @param os Device abstraction
314331766Sken * @param dma DMA descriptor for memory to be freed
315331766Sken *
316331766Sken * @return 0 if memory is de-allocated, -1 otherwise
317331766Sken */
318331766Skenint32_t
319331766Skenocs_dma_free(ocs_os_handle_t os, ocs_dma_t *dma)
320331766Sken{
321331766Sken	struct ocs_softc	*ocs = os;
322331766Sken
323331766Sken	if (!dma) {
324331766Sken		device_printf(ocs->dev, "%s: bad parameter(s) dma=%p\n", __func__, dma);
325331766Sken		return -1;
326331766Sken	}
327331766Sken
328331766Sken	if (dma->size == 0) {
329331766Sken		return 0;
330331766Sken	}
331331766Sken
332331766Sken	if (dma->map) {
333331766Sken		bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD |
334331766Sken				BUS_DMASYNC_POSTWRITE);
335331766Sken		bus_dmamap_unload(dma->tag, dma->map);
336331766Sken	}
337331766Sken
338331766Sken	if (dma->virt) {
339331766Sken		bus_dmamem_free(dma->tag, dma->virt, dma->map);
340331766Sken		bus_dmamap_destroy(dma->tag, dma->map);
341331766Sken	}
342331766Sken	bus_dma_tag_destroy(dma->tag);
343331766Sken
344331766Sken	bzero(dma, sizeof(ocs_dma_t));
345331766Sken
346331766Sken	return 0;
347331766Sken}
348331766Sken
349331766Sken/**
350331766Sken * @ingroup os
351331766Sken * @brief Allocate a DMA capable block of memory
352331766Sken *
353331766Sken * @param os Device abstraction
354331766Sken * @param dma DMA descriptor containing results of memory allocation
355331766Sken * @param size Size in bytes of desired allocation
356331766Sken * @param align Alignment in bytes
357331766Sken *
358331766Sken * @return 0 on success, ENOMEM otherwise
359331766Sken */
360331766Skenint32_t
361331766Skenocs_dma_alloc(ocs_os_handle_t os, ocs_dma_t *dma, size_t size, size_t align)
362331766Sken{
363331766Sken	struct ocs_softc	*ocs = os;
364331766Sken
365331766Sken	if (!dma || !size) {
366331766Sken		device_printf(ocs->dev, "%s bad parameter(s) dma=%p size=%zd\n",
367331766Sken				__func__, dma, size);
368331766Sken		return ENOMEM;
369331766Sken	}
370331766Sken
371331766Sken	bzero(dma, sizeof(ocs_dma_t));
372331766Sken
373331766Sken	/* create a "tag" that describes the desired memory allocation */
374331766Sken	if (bus_dma_tag_create(ocs->dmat, align, 0, BUS_SPACE_MAXADDR,
375331766Sken				BUS_SPACE_MAXADDR, NULL, NULL,
376331766Sken				size, 1, size, 0, NULL, NULL, &dma->tag)) {
377331766Sken		device_printf(ocs->dev, "DMA tag allocation failed\n");
378331766Sken		return ENOMEM;
379331766Sken	}
380331766Sken
381331766Sken	dma->size = size;
382331766Sken
383331766Sken	/* allocate the memory */
384331766Sken	if (bus_dmamem_alloc(dma->tag, &dma->virt, BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
385331766Sken				&dma->map)) {
386331766Sken		device_printf(ocs->dev, "DMA memory allocation failed s=%zd a=%zd\n", size, align);
387331766Sken		ocs_dma_free(ocs, dma);
388331766Sken		return ENOMEM;
389331766Sken	}
390331766Sken
391331766Sken	dma->alloc = dma->virt;
392331766Sken
393331766Sken	/* map virtual address to device visible address */
394331766Sken	if (bus_dmamap_load(dma->tag, dma->map, dma->virt, dma->size, ocs_dma_load,
395331766Sken				dma, 0)) {
396331766Sken		device_printf(ocs->dev, "DMA memory load failed\n");
397331766Sken		ocs_dma_free(ocs, dma);
398331766Sken		return ENOMEM;
399331766Sken	}
400331766Sken
401331766Sken	/* if the DMA map load callback fails, it sets the physical address to zero */
402331766Sken	if (0 == dma->phys) {
403331766Sken		device_printf(ocs->dev, "ocs_dma_load failed\n");
404331766Sken		ocs_dma_free(ocs, dma);
405331766Sken		return ENOMEM;
406331766Sken	}
407331766Sken
408331766Sken	return 0;
409331766Sken}
410331766Sken
411331766Sken/**
412331766Sken * @ingroup os
413331766Sken * @brief Synchronize the DMA buffer memory
414331766Sken *
415331766Sken * Ensures memory coherency between the CPU and device
416331766Sken *
417331766Sken * @param dma DMA descriptor of memory to synchronize
418331766Sken * @param flags Describes direction of synchronization
419331766Sken *   See BUS_DMA(9) for details
420331766Sken *   - BUS_DMASYNC_PREWRITE
421331766Sken *   - BUS_DMASYNC_POSTREAD
422331766Sken */
423331766Skenvoid
424331766Skenocs_dma_sync(ocs_dma_t *dma, uint32_t flags)
425331766Sken{
426331766Sken	bus_dmamap_sync(dma->tag, dma->map, flags);
427331766Sken}
428331766Sken
429331766Skenint32_t
430331766Skenocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
431331766Sken{
432331766Sken	if (!dma)
433331766Sken		return -1;
434331766Sken	if (!buffer)
435331766Sken		return -1;
436331766Sken	if (buffer_length == 0)
437331766Sken		return 0;
438331766Sken	if (buffer_length > dma->size)
439331766Sken		buffer_length = dma->size;
440331766Sken	ocs_memcpy(dma->virt, buffer, buffer_length);
441331766Sken	dma->len = buffer_length;
442331766Sken	return buffer_length;
443331766Sken}
444331766Sken
445331766Skenint32_t
446331766Skenocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
447331766Sken{
448331766Sken	if (!dma)
449331766Sken		return -1;
450331766Sken	if (!buffer)
451331766Sken		return -1;
452331766Sken	if (buffer_length == 0)
453331766Sken		return 0;
454331766Sken	if (buffer_length > dma->len)
455331766Sken		buffer_length = dma->len;
456331766Sken	ocs_memcpy(buffer, dma->virt, buffer_length);
457331766Sken	return buffer_length;
458331766Sken}
459331766Sken
460331766Sken/**
461331766Sken * @ingroup os
462331766Sken * @brief Initialize a lock
463331766Sken *
464331766Sken * @param lock lock to initialize
465331766Sken * @param name string identifier for the lock
466331766Sken */
467331766Skenvoid
468331766Skenocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...)
469331766Sken{
470331766Sken	va_list ap;
471331766Sken
472331766Sken	va_start(ap, name);
473331766Sken	ocs_vsnprintf(lock->name, MAX_LOCK_DESC_LEN, name, ap);
474331766Sken	va_end(ap);
475331766Sken
476331766Sken	mtx_init(&lock->lock, lock->name, NULL, MTX_DEF);
477331766Sken}
478331766Sken
479331766Sken/**
480331766Sken * @brief Allocate a bit map
481331766Sken *
482331766Sken * For BSD, this is a simple character string
483331766Sken *
484331766Sken * @param n_bits number of bits in bit map
485331766Sken *
486331766Sken * @return pointer to the bit map, NULL on error
487331766Sken */
488331766Skenocs_bitmap_t *
489331766Skenocs_bitmap_alloc(uint32_t n_bits)
490331766Sken{
491331766Sken
492331766Sken	return malloc(bitstr_size(n_bits), M_OCS, M_ZERO | M_NOWAIT);
493331766Sken}
494331766Sken
495331766Sken/**
496331766Sken * @brief Free a bit map
497331766Sken *
498331766Sken * @param bitmap pointer to previously allocated bit map
499331766Sken */
500331766Skenvoid
501331766Skenocs_bitmap_free(ocs_bitmap_t *bitmap)
502331766Sken{
503331766Sken
504331766Sken	free(bitmap, M_OCS);
505331766Sken}
506331766Sken
507331766Sken/**
508331766Sken * @brief find next unset bit and set it
509331766Sken *
510331766Sken * @param bitmap bit map to search
511331766Sken * @param n_bits number of bits in map
512331766Sken *
513331766Sken * @return bit position or -1 if map is full
514331766Sken */
515331766Skenint32_t
516331766Skenocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits)
517331766Sken{
518331766Sken	int32_t		position = -1;
519331766Sken
520331766Sken	bit_ffc(bitmap, n_bits, &position);
521331766Sken
522331766Sken	if (-1 != position) {
523331766Sken		bit_set(bitmap, position);
524331766Sken	}
525331766Sken
526331766Sken	return position;
527331766Sken}
528331766Sken
529331766Sken/**
530331766Sken * @brief search for next (un)set bit
531331766Sken *
532331766Sken * @param bitmap bit map to search
533331766Sken * @param set search for a set or unset bit
534331766Sken * @param n_bits number of bits in map
535331766Sken *
536331766Sken * @return bit position or -1
537331766Sken */
538331766Skenint32_t
539331766Skenocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits)
540331766Sken{
541331766Sken	int32_t		position;
542331766Sken
543331766Sken	if (!bitmap) {
544331766Sken		return -1;
545331766Sken	}
546331766Sken
547331766Sken	if (set) {
548331766Sken		bit_ffs(bitmap, n_bits, &position);
549331766Sken	} else {
550331766Sken		bit_ffc(bitmap, n_bits, &position);
551331766Sken	}
552331766Sken
553331766Sken	return position;
554331766Sken}
555331766Sken
556331766Sken/**
557331766Sken * @brief clear the specified bit
558331766Sken *
559331766Sken * @param bitmap pointer to bit map
560331766Sken * @param bit bit number to clear
561331766Sken */
562331766Skenvoid
563331766Skenocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit)
564331766Sken{
565331766Sken	bit_clear(bitmap, bit);
566331766Sken}
567331766Sken
568331766Skenvoid _ocs_log(ocs_t *ocs, const char *func_name, int line, const char *fmt, ...)
569331766Sken{
570331766Sken	va_list ap;
571331766Sken	char buf[256];
572331766Sken	char *p = buf;
573331766Sken
574331766Sken	va_start(ap, fmt);
575331766Sken
576331766Sken	/* TODO: Add Current PID info here. */
577331766Sken
578331766Sken	p += snprintf(p, sizeof(buf) - (p - buf), "%s: ", DRV_NAME);
579331766Sken	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", func_name);
580331766Sken	p += snprintf(p, sizeof(buf) - (p - buf), "%i:", line);
581331766Sken	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", (ocs != NULL) ? device_get_nameunit(ocs->dev) : "");
582331766Sken	p += vsnprintf(p, sizeof(buf) - (p - buf), fmt, ap);
583331766Sken
584331766Sken	va_end(ap);
585331766Sken
586331766Sken	printf("%s", buf);
587331766Sken}
588331766Sken
589331766Sken/**
590331766Sken * @brief Common thread call function
591331766Sken *
592331766Sken * This is the common function called whenever a thread instantiated by ocs_thread_create() is started.
593331766Sken * It captures the return value from the actual thread function and stashes it in the thread object, to
594331766Sken * be later retrieved by ocs_thread_get_retval(), and calls kthread_exit(), the proscribed method to terminate
595331766Sken * a thread.
596331766Sken *
597331766Sken * @param arg a pointer to the thread object
598331766Sken *
599331766Sken * @return none
600331766Sken */
601331766Sken
602331766Skenstatic void
603331766Skenocs_thread_call_fctn(void *arg)
604331766Sken{
605331766Sken	ocs_thread_t *thread = arg;
606331766Sken	thread->retval = (*thread->fctn)(thread->arg);
607331766Sken	ocs_free(NULL, thread->name, ocs_strlen(thread->name+1));
608331766Sken	kthread_exit();
609331766Sken}
610331766Sken
611331766Sken/**
612331766Sken * @brief Create a kernel thread
613331766Sken *
614331766Sken * Creates a kernel thread and optionally starts it.   If the thread is not immediately
615331766Sken * started, ocs_thread_start() should be called at some later point.
616331766Sken *
617331766Sken * @param os OS handle
618331766Sken * @param thread pointer to thread object
619331766Sken * @param fctn function for thread to be begin executing
620331766Sken * @param name text name to identify thread
621331766Sken * @param arg application specific argument passed to thread function
622331766Sken * @param start start option, OCS_THREAD_RUN will start the thread immediately,
623331766Sken *			OCS_THREAD_CREATE will create but not start the thread
624331766Sken *
625331766Sken * @return returns 0 for success, a negative error code value for failure.
626331766Sken */
627331766Sken
628331766Skenint32_t
629331766Skenocs_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)
630331766Sken{
631331766Sken	int32_t rc = 0;
632331766Sken
633333991Sken	ocs_memset(thread, 0, sizeof(*thread));
634331766Sken
635331766Sken	thread->fctn = fctn;
636331766Sken	thread->name = ocs_strdup(name);
637331766Sken	if (thread->name == NULL) {
638331766Sken		thread->name = "unknown";
639331766Sken	}
640331766Sken	thread->arg = arg;
641331766Sken
642331766Sken	ocs_atomic_set(&thread->terminate, 0);
643331766Sken
644331766Sken	rc = kthread_add(ocs_thread_call_fctn, thread, NULL, &thread->tcb, (start == OCS_THREAD_CREATE) ? RFSTOPPED : 0,
645331766Sken		OCS_THREAD_DEFAULT_STACK_SIZE_PAGES, "%s", name);
646331766Sken
647331766Sken	return rc;
648331766Sken}
649331766Sken
650331766Sken/**
651331766Sken * @brief Start a thread
652331766Sken *
653331766Sken * Starts a thread that was created with OCS_THREAD_CREATE rather than OCS_THREAD_RUN
654331766Sken *
655331766Sken * @param thread pointer to thread object
656331766Sken *
657331766Sken * @return returns 0 for success, a negative error code value for failure.
658331766Sken */
659331766Sken
660331766Skenint32_t ocs_thread_start(ocs_thread_t *thread)
661331766Sken{
662331766Sken	sched_add(thread->tcb, SRQ_BORING);
663331766Sken	return 0;
664331766Sken}
665331766Sken
666331766Sken/**
667331766Sken * @brief return thread argument
668331766Sken *
669331766Sken * Returns a pointer to the thread's application specific argument
670331766Sken *
671331766Sken * @param mythread pointer to the thread object
672331766Sken *
673331766Sken * @return pointer to application specific argument
674331766Sken */
675331766Sken
676331766Skenvoid *ocs_thread_get_arg(ocs_thread_t *mythread)
677331766Sken{
678331766Sken	return mythread->arg;
679331766Sken}
680331766Sken
681331766Sken/**
682331766Sken * @brief Request thread stop
683331766Sken *
684331766Sken * A stop request is made to the thread.  This is a voluntary call, the thread needs
685331766Sken * to periodically query its terminate request using ocs_thread_terminate_requested()
686331766Sken *
687331766Sken * @param thread pointer to thread object
688331766Sken *
689331766Sken * @return returns 0 for success, a negative error code value for failure.
690331766Sken */
691331766Sken
692331766Skenint32_t
693331766Skenocs_thread_terminate(ocs_thread_t *thread)
694331766Sken{
695331766Sken	ocs_atomic_set(&thread->terminate, 1);
696331766Sken	return 0;
697331766Sken}
698331766Sken
699331766Sken/**
700331766Sken * @brief See if a terminate request has been made
701331766Sken *
702331766Sken * Check to see if a stop request has been made to the current thread.  This
703331766Sken * function would be used by a thread to see if it should terminate.
704331766Sken *
705331766Sken * @return returns non-zero if a stop has been requested
706331766Sken */
707331766Sken
708331766Skenint32_t ocs_thread_terminate_requested(ocs_thread_t *thread)
709331766Sken{
710331766Sken	return ocs_atomic_read(&thread->terminate);
711331766Sken}
712331766Sken
713331766Sken/**
714331766Sken * @brief Retrieve threads return value
715331766Sken *
716331766Sken * After a thread has terminated, it's return value may be retrieved with this function.
717331766Sken *
718331766Sken * @param thread pointer to thread object
719331766Sken *
720331766Sken * @return return value from thread function
721331766Sken */
722331766Sken
723331766Skenint32_t
724331766Skenocs_thread_get_retval(ocs_thread_t *thread)
725331766Sken{
726331766Sken	return thread->retval;
727331766Sken}
728331766Sken
729331766Sken/**
730331766Sken * @brief Request that the currently running thread yield
731331766Sken *
732331766Sken * The currently running thread yields to the scheduler
733331766Sken *
734331766Sken * @param thread pointer to thread (ignored)
735331766Sken *
736331766Sken * @return none
737331766Sken */
738331766Sken
739331766Skenvoid
740331766Skenocs_thread_yield(ocs_thread_t *thread) {
741331766Sken	pause("thread yield", 1);
742331766Sken}
743331766Sken
744331766Skenocs_thread_t *
745331766Skenocs_thread_self(void)
746331766Sken{
747331766Sken	ocs_printf(">>> %s not implemented\n", __func__);
748331766Sken	ocs_abort();
749331766Sken}
750331766Sken
751331766Skenint32_t
752331766Skenocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu)
753331766Sken{
754331766Sken	ocs_printf(">>> %s not implemented\n", __func__);
755331766Sken	return -1;
756331766Sken}
757331766Sken
758331766Skenint32_t
759331766Skenocs_thread_getcpu(void)
760331766Sken{
761331766Sken	return curcpu;
762331766Sken}
763331766Sken
764331766Skenint
765331766Skenocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...)
766331766Sken{
767331766Sken	va_list ap;
768331766Sken
769331766Sken	va_start(ap, name);
770331766Sken	ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap);
771331766Sken	va_end(ap);
772331766Sken
773331766Sken	sema_init(&sem->sem, val, sem->name);
774331766Sken	return 0;
775331766Sken}
776331766Sken
777331766Sken/**
778331766Sken * @ingroup os
779331766Sken * @brief  Copy user arguments in to kernel space for an ioctl
780331766Sken * @par Description
781331766Sken * This function is called at the beginning of an ioctl function
782331766Sken * to copy the ioctl argument from user space to kernel space.
783331766Sken *
784331766Sken * BSD handles this for us - arg is already in kernel space,
785331766Sken * so we just return it.
786331766Sken *
787331766Sken * @param os OS handle
788331766Sken * @param arg The argument passed to the ioctl function
789331766Sken * @param size The size of the structure pointed to by arg
790331766Sken *
791331766Sken * @return A pointer to a kernel space copy of the argument on
792331766Sken *	success; NULL on failure
793331766Sken */
794331766Skenvoid *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size)
795331766Sken{
796331766Sken	 return arg;
797331766Sken}
798331766Sken
799331766Sken/**
800331766Sken * @ingroup os
801331766Sken * @brief  Copy results of an ioctl back to user space
802331766Sken * @par Description
803331766Sken * This function is called at the end of ioctl processing to
804331766Sken * copy the argument back to user space.
805331766Sken *
806331766Sken * BSD handles this for us.
807331766Sken *
808331766Sken * @param os OS handle
809331766Sken * @param arg The argument passed to the ioctl function
810331766Sken * @param kern_ptr A pointer to the kernel space copy of the
811331766Sken *		   argument
812331766Sken * @param size The size of the structure pointed to by arg.
813331766Sken *
814331766Sken * @return Returns 0.
815331766Sken */
816331766Skenint32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size)
817331766Sken{
818331766Sken	return 0;
819331766Sken}
820331766Sken
821331766Sken/**
822331766Sken * @ingroup os
823331766Sken * @brief  Free memory allocated by ocs_ioctl_preprocess
824331766Sken * @par Description
825331766Sken * This function is called in the event of an error in ioctl
826331766Sken * processing.  For operating environments where ocs_ioctlpreprocess
827331766Sken * allocates memory, this call frees the memory without copying
828331766Sken * results back to user space.
829331766Sken *
830331766Sken * For BSD, because no memory was allocated in ocs_ioctl_preprocess,
831331766Sken * nothing needs to be done here.
832331766Sken *
833331766Sken * @param os OS handle
834331766Sken * @param kern_ptr A pointer to the kernel space copy of the
835331766Sken *		   argument
836331766Sken * @param size The size of the structure pointed to by arg.
837331766Sken *
838331766Sken * @return Returns nothing.
839331766Sken */
840331766Skenvoid ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size)
841331766Sken{
842331766Sken	return;
843331766Sken}
844331766Sken
845331766Skenvoid ocs_intr_disable(ocs_os_handle_t os)
846331766Sken{
847331766Sken}
848331766Sken
849331766Skenvoid ocs_intr_enable(ocs_os_handle_t os)
850331766Sken{
851331766Sken}
852331766Sken
853331766Skenvoid ocs_print_stack(void)
854331766Sken{
855332883Sram#if defined(STACK)
856331766Sken	struct stack st;
857331766Sken
858331766Sken	stack_zero(&st);
859331766Sken	stack_save(&st);
860331766Sken	stack_print(&st);
861332883Sram#endif
862331766Sken}
863331766Sken
864331766Skenvoid ocs_abort(void)
865331766Sken{
866331766Sken	panic(">>> abort/panic\n");
867331766Sken}
868331766Sken
869331766Skenconst char *
870331766Skenocs_pci_model(uint16_t vendor, uint16_t device)
871331766Sken{
872331766Sken	switch (device) {
873331766Sken	case PCI_PRODUCT_EMULEX_OCE16002:	return "OCE16002";
874331766Sken	case PCI_PRODUCT_EMULEX_OCE1600_VF:	return "OCE1600_VF";
875331766Sken	case PCI_PRODUCT_EMULEX_OCE50102:	return "OCE50102";
876331766Sken	case PCI_PRODUCT_EMULEX_OCE50102_VF:	return "OCE50102_VR";
877331766Sken	default:
878331766Sken		break;
879331766Sken	}
880331766Sken
881331766Sken	return "unknown";
882331766Sken}
883331766Sken
884331766Skenint32_t
885331766Skenocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
886331766Sken{
887331766Sken	*bus = pci_get_bus(ocs->dev);
888331766Sken	*dev = pci_get_slot(ocs->dev);
889331766Sken	*func= pci_get_function(ocs->dev);
890331766Sken	return 0;
891331766Sken}
892331766Sken
893331766Sken/**
894331766Sken * @brief return CPU information
895331766Sken *
896331766Sken * This function populates the ocs_cpuinfo_t buffer with CPU information
897331766Sken *
898331766Sken * @param cpuinfo pointer to ocs_cpuinfo_t buffer
899331766Sken *
900331766Sken * @return returns 0 for success, a negative error code value for failure.
901331766Sken */
902331766Skenextern int mp_ncpus;
903331766Skenint32_t
904331766Skenocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo)
905331766Sken{
906331766Sken	cpuinfo->num_cpus = mp_ncpus;
907331766Sken	return 0;
908331766Sken}
909331766Sken
910331766Skenuint32_t
911331766Skenocs_get_num_cpus(void)
912331766Sken{
913331766Sken	static ocs_cpuinfo_t cpuinfo;
914331766Sken
915331766Sken	if (cpuinfo.num_cpus == 0) {
916331766Sken		ocs_get_cpuinfo(&cpuinfo);
917331766Sken	}
918331766Sken	return cpuinfo.num_cpus;
919331766Sken}
920331766Sken
921331766Sken
922331766Skenvoid
923331766Sken__ocs_callout(void *t)
924331766Sken{
925331766Sken	ocs_timer_t *timer = t;
926331766Sken
927331766Sken	if (callout_pending(&timer->callout)) {
928331766Sken		/* Callout was reset */
929331766Sken		return;
930331766Sken	}
931331766Sken
932331766Sken	if (!callout_active(&timer->callout)) {
933331766Sken		/* Callout was stopped */
934331766Sken		return;
935331766Sken	}
936331766Sken
937331766Sken	callout_deactivate(&timer->callout);
938331766Sken
939331766Sken	if (timer->func) {
940331766Sken		timer->func(timer->data);
941331766Sken	}
942331766Sken}
943331766Sken
944331766Skenint32_t
945331766Skenocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms)
946331766Sken{
947331766Sken	struct	timeval tv;
948331766Sken	int	hz;
949331766Sken
950331766Sken	if (timer == NULL) {
951331766Sken		ocs_log_err(NULL, "bad parameter\n");
952331766Sken		return -1;
953331766Sken	}
954331766Sken
955331766Sken	if (!mtx_initialized(&timer->lock)) {
956331766Sken		mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF);
957331766Sken	}
958331766Sken
959331766Sken	callout_init_mtx(&timer->callout, &timer->lock, 0);
960331766Sken
961331766Sken	timer->func = func;
962331766Sken	timer->data = data;
963331766Sken
964331766Sken	tv.tv_sec  = timeout_ms / 1000;
965331766Sken	tv.tv_usec = (timeout_ms % 1000) * 1000;
966331766Sken
967331766Sken	hz = tvtohz(&tv);
968331766Sken	if (hz < 0)
969331766Sken		hz = INT32_MAX;
970331766Sken	if (hz == 0)
971331766Sken		hz = 1;
972331766Sken
973331766Sken	mtx_lock(&timer->lock);
974331766Sken		callout_reset(&timer->callout, hz, __ocs_callout, timer);
975331766Sken	mtx_unlock(&timer->lock);
976331766Sken
977331766Sken	return 0;
978331766Sken}
979331766Sken
980331766Skenint32_t
981331766Skenocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms)
982331766Sken{
983331766Sken	struct	timeval tv;
984331766Sken	int	hz;
985331766Sken
986331766Sken	if (timer == NULL) {
987331766Sken		ocs_log_err(NULL, "bad parameter\n");
988331766Sken		return -1;
989331766Sken	}
990331766Sken
991331766Sken	tv.tv_sec  = timeout_ms / 1000;
992331766Sken	tv.tv_usec = (timeout_ms % 1000) * 1000;
993331766Sken
994331766Sken	hz = tvtohz(&tv);
995331766Sken	if (hz < 0)
996331766Sken		hz = INT32_MAX;
997331766Sken	if (hz == 0)
998331766Sken		hz = 1;
999331766Sken
1000331766Sken	mtx_lock(&timer->lock);
1001331766Sken		callout_reset(&timer->callout, hz, __ocs_callout, timer);
1002331766Sken	mtx_unlock(&timer->lock);
1003331766Sken
1004331766Sken	return 0;
1005331766Sken}
1006331766Sken
1007331766Skenint32_t
1008331766Skenocs_timer_pending(ocs_timer_t *timer)
1009331766Sken{
1010331766Sken	return callout_active(&timer->callout);
1011331766Sken}
1012331766Sken
1013331766Skenint32_t
1014331766Skenocs_del_timer(ocs_timer_t *timer)
1015331766Sken{
1016331766Sken
1017331766Sken	mtx_lock(&timer->lock);
1018331766Sken		callout_stop(&timer->callout);
1019331766Sken	mtx_unlock(&timer->lock);
1020331766Sken
1021331766Sken	return 0;
1022331766Sken}
1023331766Sken
1024331766Skenchar *
1025331766Skenocs_strdup(const char *s)
1026331766Sken{
1027331766Sken	uint32_t l = strlen(s);
1028331766Sken	char *d;
1029331766Sken
1030331766Sken	d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT);
1031331766Sken	if (d != NULL) {
1032331766Sken		ocs_strcpy(d, s);
1033331766Sken	}
1034331766Sken	return d;
1035331766Sken}
1036331766Sken
1037331766Skenvoid
1038331766Sken_ocs_assert(const char *cond, const char *filename, int linenum)
1039331766Sken{
1040331766Sken	const char *fn = strrchr(__FILE__, '/');
1041331766Sken
1042331766Sken	ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond);
1043331766Sken	ocs_print_stack();
1044331766Sken	ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE);
1045331766Sken}
1046