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