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