The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ocs_fc/ocs_gendump.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2021 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 #include "ocs.h"
   34 #include "ocs_gendump.h"
   35 
   36 /* Reset all the functions associated with a bus/dev */
   37 static int
   38 ocs_gen_dump_reset(uint8_t bus, uint8_t dev)
   39 {
   40         uint32_t index = 0;
   41         ocs_t *ocs;
   42         int rc = 0;
   43 
   44         while ((ocs = ocs_get_instance(index++)) != NULL) {
   45                 uint8_t ocs_bus, ocs_dev, ocs_func;
   46                 ocs_domain_t *domain;
   47 
   48                 ocs_get_bus_dev_func(ocs, &ocs_bus, &ocs_dev, &ocs_func);
   49 
   50                 if (!(ocs_bus == bus && ocs_dev == dev))
   51                         continue;
   52 
   53                 if (ocs_hw_reset(&ocs->hw, OCS_HW_RESET_FUNCTION)) {
   54                         ocs_log_test(ocs, "failed to reset port\n");
   55                         rc = -1;
   56                         continue;
   57                 }
   58 
   59                 ocs_log_debug(ocs, "successfully reset port\n");
   60                 while ((domain = ocs_list_get_head(&ocs->domain_list)) != NULL) {
   61                         ocs_log_debug(ocs, "free domain %p\n", domain);
   62                         ocs_domain_force_free(domain);
   63                 }
   64                 /* now initialize hw so user can read the dump in */
   65                 if (ocs_hw_init(&ocs->hw)) {
   66                         ocs_log_err(ocs, "failed to initialize hw\n");
   67                         rc = -1;
   68                 } else {
   69                         ocs_log_debug(ocs, "successfully initialized hw\n");
   70                 }
   71         }
   72         return rc;
   73 }
   74 
   75 int
   76 ocs_gen_dump(ocs_t *ocs)
   77 {
   78         uint32_t reset_required;
   79         uint32_t dump_ready;
   80         uint32_t ms_waited;
   81         uint8_t bus, dev, func;
   82         int rc = 0;
   83         int index = 0, port_index = 0;
   84         ocs_t *nxt_ocs;
   85         uint8_t nxt_bus, nxt_dev, nxt_func;
   86         uint8_t prev_port_state[OCS_MAX_HBA_PORTS] = {0,};
   87         ocs_xport_stats_t link_status;
   88 
   89         ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
   90 
   91         /* Drop link on all ports belongs to this HBA*/
   92         while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
   93                 ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
   94 
   95                 if (!(bus == nxt_bus && dev == nxt_dev))
   96                         continue;
   97 
   98                 if ((port_index >= OCS_MAX_HBA_PORTS))
   99                         continue;
  100 
  101                 /* Check current link status and save for future use */
  102                 if (ocs_xport_status(nxt_ocs->xport, OCS_XPORT_PORT_STATUS,
  103                    &link_status) == 0) {
  104                         if (link_status.value == OCS_XPORT_PORT_ONLINE) {
  105                                 prev_port_state[port_index] = 1;
  106                                 ocs_xport_control(nxt_ocs->xport,
  107                                                   OCS_XPORT_PORT_OFFLINE);
  108                         } else {
  109                                 prev_port_state[port_index] = 0;
  110                         }
  111                 }
  112                 port_index++;
  113         }
  114 
  115         /* Wait until all ports have quiesced */
  116         for (index = 0; (nxt_ocs = ocs_get_instance(index++)) != NULL; ) {
  117                 ms_waited = 0;
  118                 for (;;) {
  119                         ocs_xport_stats_t status;
  120 
  121                         ocs_xport_status(nxt_ocs->xport, OCS_XPORT_IS_QUIESCED,
  122                                          &status);
  123                         if (status.value) {
  124                                 ocs_log_debug(nxt_ocs, "port quiesced\n");
  125                                 break;
  126                         }
  127 
  128                         ocs_msleep(10);
  129                         ms_waited += 10;
  130                         if (ms_waited > 60000) {
  131                                 ocs_log_test(nxt_ocs,
  132                                     "timed out waiting for port to quiesce\n");
  133                                 break;
  134                         }
  135                 }
  136         }
  137 
  138         /* Initiate dump */
  139         if (ocs_hw_raise_ue(&ocs->hw, 1) == OCS_HW_RTN_SUCCESS) {
  140 
  141                 /* Wait for dump to complete */
  142                 ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
  143 
  144                 dump_ready = 0;
  145                 ms_waited = 0;
  146                 while ((!dump_ready) && (ms_waited < 30000)) {
  147                         ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
  148                         ocs_udelay(10000);
  149                         ms_waited += 10;
  150                 }
  151 
  152                 if (!dump_ready) {
  153                         ocs_log_test(ocs, "Failed to see dump after 30 secs\n");
  154                         rc = -1;
  155                 } else {
  156                         ocs_log_debug(ocs, "sucessfully generated dump\n");
  157                 }
  158 
  159                 /* now reset port */
  160                 ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required);
  161                 ocs_log_debug(ocs, "reset required=%d\n", reset_required);
  162                 if (reset_required) {
  163                         if (ocs_gen_dump_reset(bus, dev) == 0) {
  164                                 ocs_log_debug(ocs, "all devices reset\n");
  165                         } else {
  166                                 ocs_log_test(ocs, "all devices NOT reset\n");
  167                         }
  168                 }
  169         } else {
  170                 ocs_log_test(ocs, "dump request to hw failed\n");
  171                 rc = -1;
  172         }
  173 
  174         index = port_index = 0;
  175         nxt_ocs = NULL;
  176         /* Bring links on each HBA port to previous state*/
  177         while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
  178                 ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
  179                 if (port_index > OCS_MAX_HBA_PORTS) {
  180                         ocs_log_err(NULL, "port index(%d) out of boundary\n",
  181                                     port_index);
  182                         rc = -1;
  183                         break;
  184                 }
  185                 if ((bus == nxt_bus) && (dev == nxt_dev) &&
  186                     prev_port_state[port_index++]) {
  187                         ocs_xport_control(nxt_ocs->xport, OCS_XPORT_PORT_ONLINE);
  188                 }
  189         }
  190 
  191         return rc;
  192 }
  193 
  194 int
  195 ocs_fdb_dump(ocs_t *ocs)
  196 {
  197         uint32_t dump_ready;
  198         uint32_t ms_waited;
  199         int rc = 0;
  200 
  201 #define FDB 2
  202 
  203         /* Initiate dump */
  204         if (ocs_hw_raise_ue(&ocs->hw, FDB) == OCS_HW_RTN_SUCCESS) {
  205 
  206                 /* Wait for dump to complete */
  207                 ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
  208 
  209                 dump_ready = 0;
  210                 ms_waited = 0;
  211                 while ((!(dump_ready == FDB)) && (ms_waited < 10000)) {
  212                         ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
  213                         ocs_udelay(10000);
  214                         ms_waited += 10;
  215                 }
  216 
  217                 if (!dump_ready) {
  218                         ocs_log_err(ocs, "Failed to see dump after 10 secs\n");
  219                         return -1;
  220                 }
  221 
  222                 ocs_log_debug(ocs, "sucessfully generated dump\n");
  223 
  224         } else {
  225                 ocs_log_err(ocs, "dump request to hw failed\n");
  226                 rc = -1;
  227         }
  228 
  229         return rc;
  230 }
  231 
  232 /**
  233  * @brief Create a Lancer dump into a memory buffer
  234  * @par Description
  235  * This function creates a DMA buffer to hold a Lancer dump,
  236  * sets the dump location to point to that buffer, then calls
  237  * ocs_gen_dump to cause a dump to be transferred to the buffer.
  238  * After the dump is complete it copies the dump to the provided
  239  * user space buffer.
  240  *
  241  * @param ocs Pointer to ocs structure
  242  * @param buf User space buffer in which to store the dump
  243  * @param buflen Length of the user buffer in bytes
  244  *
  245  * @return Returns 0 on success, non-zero on error.
  246  */
  247 int
  248 ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen)
  249 {
  250         int rc;
  251         uint32_t i, num_buffers;
  252         ocs_dma_t *dump_buffers;
  253         uint32_t rem_bytes, offset;
  254 
  255         if (buflen == 0) {
  256                 ocs_log_test(ocs, "zero buffer length is invalid\n");
  257                 return -1;
  258         }
  259 
  260         num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
  261 
  262         dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
  263                                   OCS_M_ZERO | OCS_M_NOWAIT);
  264         if (dump_buffers == NULL) {
  265                 ocs_log_err(ocs, "Failed to dump buffers\n");
  266                 return -1;
  267         }
  268 
  269         /* Allocate a DMA buffers to hold the dump */
  270         rem_bytes = buflen;
  271         for (i = 0; i < num_buffers; i++) {
  272                 uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
  273 
  274                 rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
  275                                    OCS_MIN_DMA_ALIGNMENT);
  276                 if (rc) {
  277                         ocs_log_err(ocs, "Failed to allocate dump buffer\n");
  278 
  279                         /* Free any previously allocated buffers */
  280                         goto free_and_return;
  281                 }
  282                 rem_bytes -= num_bytes;
  283         }
  284 
  285         rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 0);
  286         if (rc) {
  287                 ocs_log_test(ocs, "ocs_hw_set_dump_location failed\n");
  288                 goto free_and_return;
  289         }
  290 
  291         /* Generate the dump */
  292         rc = ocs_gen_dump(ocs);
  293         if (rc) {
  294                 ocs_log_test(ocs, "ocs_gen_dump failed\n");
  295                 goto free_and_return;
  296         }
  297 
  298         /* Copy the dump from the DMA buffer into the user buffer */
  299         offset = 0;
  300         for (i = 0; i < num_buffers; i++) {
  301                 if (ocs_copy_to_user((uint8_t*)buf + offset,
  302                     dump_buffers[i].virt, dump_buffers[i].size)) {
  303                         ocs_log_test(ocs, "ocs_copy_to_user failed\n");
  304                         rc = -1;
  305                 }
  306                 offset += dump_buffers[i].size;
  307         }
  308 
  309 free_and_return:
  310         /* Free the DMA buffer and return */
  311         for (i = 0; i < num_buffers; i++) {
  312                 ocs_dma_free(ocs, &dump_buffers[i]);
  313         }
  314         ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
  315         return rc;
  316 }
  317 
  318 int
  319 ocs_function_speciic_dump(ocs_t *ocs, void *buf, uint32_t buflen)
  320 {
  321         int rc;
  322         uint32_t i, num_buffers;
  323         ocs_dma_t *dump_buffers;
  324         uint32_t rem_bytes, offset;
  325 
  326         if (buflen == 0) {
  327                 ocs_log_err(ocs, "zero buffer length is invalid\n");
  328                 return -1;
  329         }
  330 
  331         num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
  332 
  333         dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
  334                                   OCS_M_ZERO | OCS_M_NOWAIT);
  335         if (dump_buffers == NULL) {
  336                 ocs_log_err(ocs, "Failed to allocate dump buffers\n");
  337                 return -1;
  338         }
  339 
  340         /* Allocate a DMA buffers to hold the dump */
  341         rem_bytes = buflen;
  342         for (i = 0; i < num_buffers; i++) {
  343                 uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
  344                 rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
  345                                    OCS_MIN_DMA_ALIGNMENT);
  346                 if (rc) {
  347                         ocs_log_err(ocs, "Failed to allocate dma buffer\n");
  348 
  349                         /* Free any previously allocated buffers */
  350                         goto free_and_return;
  351                 }
  352                 rem_bytes -= num_bytes;
  353         }
  354 
  355         /* register buffers for function spcific dump */
  356         rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 1);
  357         if (rc) {
  358                 ocs_log_err(ocs, "ocs_hw_set_dump_location failed\n");
  359                 goto free_and_return;
  360         }
  361 
  362         /* Invoke dump by setting fdd=1 and ip=1 in sliport_control register */
  363         rc = ocs_fdb_dump(ocs);
  364         if (rc) {
  365                 ocs_log_err(ocs, "ocs_gen_dump failed\n");
  366                 goto free_and_return;
  367         }
  368 
  369         /* Copy the dump from the DMA buffer into the user buffer */
  370         offset = 0;
  371         for (i = 0; i < num_buffers; i++) {
  372                 if (ocs_copy_to_user((uint8_t*)buf + offset,
  373                     dump_buffers[i].virt, dump_buffers[i].size)) {
  374                         ocs_log_err(ocs, "ocs_copy_to_user failed\n");
  375                         rc = -1;
  376                 }
  377                 offset += dump_buffers[i].size;
  378         }
  379 
  380 free_and_return:
  381         /* Free the DMA buffer and return */
  382         for (i = 0; i < num_buffers; i++) {
  383                 ocs_dma_free(ocs, &dump_buffers[i]);
  384         }
  385         ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
  386         return rc;
  387 
  388 }

Cache object: 9ac9ff430d2046f938ce0fbc1442f844


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.