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 callout_func_t __ocs_callout; 49 50 uint32_t 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 563 ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit) 564 { 565 bit_clear(bitmap, bit); 566 } 567 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 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 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 660 int32_t ocs_thread_start(ocs_thread_t *thread) 661 { 662 663 thread_lock(thread->tcb); 664 sched_add(thread->tcb, SRQ_BORING); 665 return 0; 666 } 667 668 /** 669 * @brief return thread argument 670 * 671 * Returns a pointer to the thread's application specific argument 672 * 673 * @param mythread pointer to the thread object 674 * 675 * @return pointer to application specific argument 676 */ 677 678 void *ocs_thread_get_arg(ocs_thread_t *mythread) 679 { 680 return mythread->arg; 681 } 682 683 /** 684 * @brief Request thread stop 685 * 686 * A stop request is made to the thread. This is a voluntary call, the thread needs 687 * to periodically query its terminate request using ocs_thread_terminate_requested() 688 * 689 * @param thread pointer to thread object 690 * 691 * @return returns 0 for success, a negative error code value for failure. 692 */ 693 694 int32_t 695 ocs_thread_terminate(ocs_thread_t *thread) 696 { 697 ocs_atomic_set(&thread->terminate, 1); 698 return 0; 699 } 700 701 /** 702 * @brief See if a terminate request has been made 703 * 704 * Check to see if a stop request has been made to the current thread. This 705 * function would be used by a thread to see if it should terminate. 706 * 707 * @return returns non-zero if a stop has been requested 708 */ 709 710 int32_t ocs_thread_terminate_requested(ocs_thread_t *thread) 711 { 712 return ocs_atomic_read(&thread->terminate); 713 } 714 715 /** 716 * @brief Retrieve threads return value 717 * 718 * After a thread has terminated, it's return value may be retrieved with this function. 719 * 720 * @param thread pointer to thread object 721 * 722 * @return return value from thread function 723 */ 724 725 int32_t 726 ocs_thread_get_retval(ocs_thread_t *thread) 727 { 728 return thread->retval; 729 } 730 731 /** 732 * @brief Request that the currently running thread yield 733 * 734 * The currently running thread yields to the scheduler 735 * 736 * @param thread pointer to thread (ignored) 737 * 738 * @return none 739 */ 740 741 void 742 ocs_thread_yield(ocs_thread_t *thread) { 743 pause("thread yield", 1); 744 } 745 746 ocs_thread_t * 747 ocs_thread_self(void) 748 { 749 ocs_printf(">>> %s not implemented\n", __func__); 750 ocs_abort(); 751 } 752 753 int32_t 754 ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu) 755 { 756 ocs_printf(">>> %s not implemented\n", __func__); 757 return -1; 758 } 759 760 int32_t 761 ocs_thread_getcpu(void) 762 { 763 return curcpu; 764 } 765 766 int 767 ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) 768 { 769 va_list ap; 770 771 va_start(ap, name); 772 ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap); 773 va_end(ap); 774 775 sema_init(&sem->sem, val, sem->name); 776 return 0; 777 } 778 779 /** 780 * @ingroup os 781 * @brief Copy user arguments in to kernel space for an ioctl 782 * @par Description 783 * This function is called at the beginning of an ioctl function 784 * to copy the ioctl argument from user space to kernel space. 785 * 786 * BSD handles this for us - arg is already in kernel space, 787 * so we just return it. 788 * 789 * @param os OS handle 790 * @param arg The argument passed to the ioctl function 791 * @param size The size of the structure pointed to by arg 792 * 793 * @return A pointer to a kernel space copy of the argument on 794 * success; NULL on failure 795 */ 796 void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size) 797 { 798 return arg; 799 } 800 801 /** 802 * @ingroup os 803 * @brief Copy results of an ioctl back to user space 804 * @par Description 805 * This function is called at the end of ioctl processing to 806 * copy the argument back to user space. 807 * 808 * BSD handles this for us. 809 * 810 * @param os OS handle 811 * @param arg The argument passed to the ioctl function 812 * @param kern_ptr A pointer to the kernel space copy of the 813 * argument 814 * @param size The size of the structure pointed to by arg. 815 * 816 * @return Returns 0. 817 */ 818 int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size) 819 { 820 return 0; 821 } 822 823 /** 824 * @ingroup os 825 * @brief Free memory allocated by ocs_ioctl_preprocess 826 * @par Description 827 * This function is called in the event of an error in ioctl 828 * processing. For operating environments where ocs_ioctlpreprocess 829 * allocates memory, this call frees the memory without copying 830 * results back to user space. 831 * 832 * For BSD, because no memory was allocated in ocs_ioctl_preprocess, 833 * nothing needs to be done here. 834 * 835 * @param os OS handle 836 * @param kern_ptr A pointer to the kernel space copy of the 837 * argument 838 * @param size The size of the structure pointed to by arg. 839 * 840 * @return Returns nothing. 841 */ 842 void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size) 843 { 844 return; 845 } 846 847 void ocs_intr_disable(ocs_os_handle_t os) 848 { 849 } 850 851 void ocs_intr_enable(ocs_os_handle_t os) 852 { 853 } 854 855 void ocs_print_stack(void) 856 { 857 #if defined(STACK) 858 struct stack st; 859 860 stack_zero(&st); 861 stack_save(&st); 862 stack_print(&st); 863 #endif 864 } 865 866 void ocs_abort(void) 867 { 868 panic(">>> abort/panic\n"); 869 } 870 871 const char * 872 ocs_pci_model(uint16_t vendor, uint16_t device) 873 { 874 switch (device) { 875 case PCI_PRODUCT_EMULEX_OCE16002: return "OCE16002"; 876 case PCI_PRODUCT_EMULEX_OCE1600_VF: return "OCE1600_VF"; 877 case PCI_PRODUCT_EMULEX_OCE50102: return "OCE50102"; 878 case PCI_PRODUCT_EMULEX_OCE50102_VF: return "OCE50102_VR"; 879 default: 880 break; 881 } 882 883 return "unknown"; 884 } 885 886 void 887 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func) 888 { 889 *bus = pci_get_bus(ocs->dev); 890 *dev = pci_get_slot(ocs->dev); 891 *func= pci_get_function(ocs->dev); 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 void 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 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 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 1008 ocs_timer_pending(ocs_timer_t *timer) 1009 { 1010 return callout_active(&timer->callout); 1011 } 1012 1013 int32_t 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 * 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 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