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