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 39static 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 46callout_func_t __ocs_callout; 47 48uint32_t 49ocs_config_read32(ocs_os_handle_t os, uint32_t reg) 50{ 51 return pci_read_config(os->dev, reg, 4); 52} 53 54uint16_t 55ocs_config_read16(ocs_os_handle_t os, uint32_t reg) 56{ 57 return pci_read_config(os->dev, reg, 2); 58} 59 60uint8_t 61ocs_config_read8(ocs_os_handle_t os, uint32_t reg) 62{ 63 return pci_read_config(os->dev, reg, 1); 64} 65 66void 67ocs_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 72void 73ocs_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 78void 79ocs_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 */ 98uint32_t 99ocs_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 */ 122uint16_t 123ocs_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 */ 146uint8_t 147ocs_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 */ 171void 172ocs_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 */ 196void 197ocs_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 */ 221void 222ocs_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 */ 241void * 242ocs_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 */ 272void 273ocs_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 */ 294static void 295ocs_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 */ 316int32_t 317ocs_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 */ 358int32_t 359ocs_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 */ 421void 422ocs_dma_sync(ocs_dma_t *dma, uint32_t flags) 423{ 424 bus_dmamap_sync(dma->tag, dma->map, flags); 425} 426 427int32_t 428ocs_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 443int32_t 444ocs_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 */ 465void 466ocs_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 */ 486ocs_bitmap_t * 487ocs_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 */ 498void 499ocs_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 */ 513int32_t 514ocs_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 */ 536int32_t 537ocs_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 */ 560void 561ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit) 562{ 563 bit_clear(bitmap, bit); 564} 565 566void _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 600static void 601ocs_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 626int32_t 627ocs_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 658int32_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 676void *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 692int32_t 693ocs_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 708int32_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 723int32_t 724ocs_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 739void 740ocs_thread_yield(ocs_thread_t *thread) { 741 pause("thread yield", 1); 742} 743 744ocs_thread_t * 745ocs_thread_self(void) 746{ 747 ocs_printf(">>> %s not implemented\n", __func__); 748 ocs_abort(); 749} 750 751int32_t 752ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu) 753{ 754 ocs_printf(">>> %s not implemented\n", __func__); 755 return -1; 756} 757 758int32_t 759ocs_thread_getcpu(void) 760{ 761 return curcpu; 762} 763 764int 765ocs_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 */ 794void *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 */ 816int32_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 */ 840void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size) 841{ 842 return; 843} 844 845void ocs_intr_disable(ocs_os_handle_t os) 846{ 847} 848 849void ocs_intr_enable(ocs_os_handle_t os) 850{ 851} 852 853void 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 863void ocs_abort(void) 864{ 865 panic(">>> abort/panic\n"); 866} 867 868const char * 869ocs_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 883void 884ocs_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 */ 900extern int mp_ncpus; 901int32_t 902ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo) 903{ 904 cpuinfo->num_cpus = mp_ncpus; 905 return 0; 906} 907 908uint32_t 909ocs_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 919void 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 941int32_t 942ocs_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 977int32_t 978ocs_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 1004int32_t 1005ocs_timer_pending(ocs_timer_t *timer) 1006{ 1007 return callout_active(&timer->callout); 1008} 1009 1010int32_t 1011ocs_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 1021char * 1022ocs_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 1034void 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