ocs_fc: Add gendump and dump_to_host ioctl command support.
Support to generate firmware dump. Approved by: mav(mentor)
This commit is contained in:
parent
2b2c460d7b
commit
29e2dbd42c
388
sys/dev/ocs_fc/ocs_gendump.c
Normal file
388
sys/dev/ocs_fc/ocs_gendump.c
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Broadcom. All rights reserved.
|
||||||
|
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ocs.h"
|
||||||
|
#include "ocs_gendump.h"
|
||||||
|
|
||||||
|
/* Reset all the functions associated with a bus/dev */
|
||||||
|
static int
|
||||||
|
ocs_gen_dump_reset(uint8_t bus, uint8_t dev)
|
||||||
|
{
|
||||||
|
uint32_t index = 0;
|
||||||
|
ocs_t *ocs;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
while ((ocs = ocs_get_instance(index++)) != NULL) {
|
||||||
|
uint8_t ocs_bus, ocs_dev, ocs_func;
|
||||||
|
ocs_domain_t *domain;
|
||||||
|
|
||||||
|
ocs_get_bus_dev_func(ocs, &ocs_bus, &ocs_dev, &ocs_func);
|
||||||
|
|
||||||
|
if (!(ocs_bus == bus && ocs_dev == dev))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ocs_hw_reset(&ocs->hw, OCS_HW_RESET_FUNCTION)) {
|
||||||
|
ocs_log_test(ocs, "failed to reset port\n");
|
||||||
|
rc = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocs_log_debug(ocs, "successfully reset port\n");
|
||||||
|
while ((domain = ocs_list_get_head(&ocs->domain_list)) != NULL) {
|
||||||
|
ocs_log_debug(ocs, "free domain %p\n", domain);
|
||||||
|
ocs_domain_force_free(domain);
|
||||||
|
}
|
||||||
|
/* now initialize hw so user can read the dump in */
|
||||||
|
if (ocs_hw_init(&ocs->hw)) {
|
||||||
|
ocs_log_err(ocs, "failed to initialize hw\n");
|
||||||
|
rc = -1;
|
||||||
|
} else {
|
||||||
|
ocs_log_debug(ocs, "successfully initialized hw\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ocs_gen_dump(ocs_t *ocs)
|
||||||
|
{
|
||||||
|
uint32_t reset_required;
|
||||||
|
uint32_t dump_ready;
|
||||||
|
uint32_t ms_waited;
|
||||||
|
uint8_t bus, dev, func;
|
||||||
|
int rc = 0;
|
||||||
|
int index = 0, port_index = 0;
|
||||||
|
ocs_t *nxt_ocs;
|
||||||
|
uint8_t nxt_bus, nxt_dev, nxt_func;
|
||||||
|
uint8_t prev_port_state[OCS_MAX_HBA_PORTS] = {0,};
|
||||||
|
ocs_xport_stats_t link_status;
|
||||||
|
|
||||||
|
ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
|
||||||
|
|
||||||
|
/* Drop link on all ports belongs to this HBA*/
|
||||||
|
while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
|
||||||
|
ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
|
||||||
|
|
||||||
|
if (!(bus == nxt_bus && dev == nxt_dev))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((port_index >= OCS_MAX_HBA_PORTS))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check current link status and save for future use */
|
||||||
|
if (ocs_xport_status(nxt_ocs->xport, OCS_XPORT_PORT_STATUS,
|
||||||
|
&link_status) == 0) {
|
||||||
|
if (link_status.value == OCS_XPORT_PORT_ONLINE) {
|
||||||
|
prev_port_state[port_index] = 1;
|
||||||
|
ocs_xport_control(nxt_ocs->xport,
|
||||||
|
OCS_XPORT_PORT_OFFLINE);
|
||||||
|
} else {
|
||||||
|
prev_port_state[port_index] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until all ports have quiesced */
|
||||||
|
for (index = 0; (nxt_ocs = ocs_get_instance(index++)) != NULL; ) {
|
||||||
|
ms_waited = 0;
|
||||||
|
for (;;) {
|
||||||
|
ocs_xport_stats_t status;
|
||||||
|
|
||||||
|
ocs_xport_status(nxt_ocs->xport, OCS_XPORT_IS_QUIESCED,
|
||||||
|
&status);
|
||||||
|
if (status.value) {
|
||||||
|
ocs_log_debug(nxt_ocs, "port quiesced\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocs_msleep(10);
|
||||||
|
ms_waited += 10;
|
||||||
|
if (ms_waited > 60000) {
|
||||||
|
ocs_log_test(nxt_ocs,
|
||||||
|
"timed out waiting for port to quiesce\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initiate dump */
|
||||||
|
if (ocs_hw_raise_ue(&ocs->hw, 1) == OCS_HW_RTN_SUCCESS) {
|
||||||
|
|
||||||
|
/* Wait for dump to complete */
|
||||||
|
ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
|
||||||
|
|
||||||
|
dump_ready = 0;
|
||||||
|
ms_waited = 0;
|
||||||
|
while ((!dump_ready) && (ms_waited < 30000)) {
|
||||||
|
ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
|
||||||
|
ocs_udelay(10000);
|
||||||
|
ms_waited += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dump_ready) {
|
||||||
|
ocs_log_test(ocs, "Failed to see dump after 30 secs\n");
|
||||||
|
rc = -1;
|
||||||
|
} else {
|
||||||
|
ocs_log_debug(ocs, "sucessfully generated dump\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now reset port */
|
||||||
|
ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required);
|
||||||
|
ocs_log_debug(ocs, "reset required=%d\n", reset_required);
|
||||||
|
if (reset_required) {
|
||||||
|
if (ocs_gen_dump_reset(bus, dev) == 0) {
|
||||||
|
ocs_log_debug(ocs, "all devices reset\n");
|
||||||
|
} else {
|
||||||
|
ocs_log_test(ocs, "all devices NOT reset\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ocs_log_test(ocs, "dump request to hw failed\n");
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = port_index = 0;
|
||||||
|
nxt_ocs = NULL;
|
||||||
|
/* Bring links on each HBA port to previous state*/
|
||||||
|
while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
|
||||||
|
ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
|
||||||
|
if (port_index > OCS_MAX_HBA_PORTS) {
|
||||||
|
ocs_log_err(NULL, "port index(%d) out of boundary\n",
|
||||||
|
port_index);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((bus == nxt_bus) && (dev == nxt_dev) &&
|
||||||
|
prev_port_state[port_index++]) {
|
||||||
|
ocs_xport_control(nxt_ocs->xport, OCS_XPORT_PORT_ONLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ocs_fdb_dump(ocs_t *ocs)
|
||||||
|
{
|
||||||
|
uint32_t dump_ready;
|
||||||
|
uint32_t ms_waited;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
#define FDB 2
|
||||||
|
|
||||||
|
/* Initiate dump */
|
||||||
|
if (ocs_hw_raise_ue(&ocs->hw, FDB) == OCS_HW_RTN_SUCCESS) {
|
||||||
|
|
||||||
|
/* Wait for dump to complete */
|
||||||
|
ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
|
||||||
|
|
||||||
|
dump_ready = 0;
|
||||||
|
ms_waited = 0;
|
||||||
|
while ((!(dump_ready == FDB)) && (ms_waited < 10000)) {
|
||||||
|
ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
|
||||||
|
ocs_udelay(10000);
|
||||||
|
ms_waited += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dump_ready) {
|
||||||
|
ocs_log_err(ocs, "Failed to see dump after 10 secs\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocs_log_debug(ocs, "sucessfully generated dump\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ocs_log_err(ocs, "dump request to hw failed\n");
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Lancer dump into a memory buffer
|
||||||
|
* @par Description
|
||||||
|
* This function creates a DMA buffer to hold a Lancer dump,
|
||||||
|
* sets the dump location to point to that buffer, then calls
|
||||||
|
* ocs_gen_dump to cause a dump to be transfered to the buffer.
|
||||||
|
* After the dump is complete it copies the dump to the provided
|
||||||
|
* user space buffer.
|
||||||
|
*
|
||||||
|
* @param ocs Pointer to ocs structure
|
||||||
|
* @param buf User space buffer in which to store the dump
|
||||||
|
* @param buflen Length of the user buffer in bytes
|
||||||
|
*
|
||||||
|
* @return Returns 0 on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t i, num_buffers;
|
||||||
|
ocs_dma_t *dump_buffers;
|
||||||
|
uint32_t rem_bytes, offset;
|
||||||
|
|
||||||
|
if (buflen == 0) {
|
||||||
|
ocs_log_test(ocs, "zero buffer length is invalid\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
|
||||||
|
|
||||||
|
dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
|
||||||
|
OCS_M_ZERO | OCS_M_NOWAIT);
|
||||||
|
if (dump_buffers == NULL) {
|
||||||
|
ocs_log_err(ocs, "Failed to dump buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a DMA buffers to hold the dump */
|
||||||
|
rem_bytes = buflen;
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
|
||||||
|
|
||||||
|
rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
|
||||||
|
OCS_MIN_DMA_ALIGNMENT);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_err(ocs, "Failed to allocate dump buffer\n");
|
||||||
|
|
||||||
|
/* Free any previously allocated buffers */
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
rem_bytes -= num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 0);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_test(ocs, "ocs_hw_set_dump_location failed\n");
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate the dump */
|
||||||
|
rc = ocs_gen_dump(ocs);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_test(ocs, "ocs_gen_dump failed\n");
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the dump from the DMA buffer into the user buffer */
|
||||||
|
offset = 0;
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
if (ocs_copy_to_user((uint8_t*)buf + offset,
|
||||||
|
dump_buffers[i].virt, dump_buffers[i].size)) {
|
||||||
|
ocs_log_test(ocs, "ocs_copy_to_user failed\n");
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
offset += dump_buffers[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_and_return:
|
||||||
|
/* Free the DMA buffer and return */
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
ocs_dma_free(ocs, &dump_buffers[i]);
|
||||||
|
}
|
||||||
|
ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ocs_function_speciic_dump(ocs_t *ocs, void *buf, uint32_t buflen)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t i, num_buffers;
|
||||||
|
ocs_dma_t *dump_buffers;
|
||||||
|
uint32_t rem_bytes, offset;
|
||||||
|
|
||||||
|
if (buflen == 0) {
|
||||||
|
ocs_log_err(ocs, "zero buffer length is invalid\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
|
||||||
|
|
||||||
|
dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
|
||||||
|
OCS_M_ZERO | OCS_M_NOWAIT);
|
||||||
|
if (dump_buffers == NULL) {
|
||||||
|
ocs_log_err(ocs, "Failed to allocate dump buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a DMA buffers to hold the dump */
|
||||||
|
rem_bytes = buflen;
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
|
||||||
|
rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
|
||||||
|
OCS_MIN_DMA_ALIGNMENT);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_err(ocs, "Failed to allocate dma buffer\n");
|
||||||
|
|
||||||
|
/* Free any previously allocated buffers */
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
rem_bytes -= num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* register buffers for function spcific dump */
|
||||||
|
rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 1);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_err(ocs, "ocs_hw_set_dump_location failed\n");
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invoke dump by setting fdd=1 and ip=1 in sliport_control register */
|
||||||
|
rc = ocs_fdb_dump(ocs);
|
||||||
|
if (rc) {
|
||||||
|
ocs_log_err(ocs, "ocs_gen_dump failed\n");
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the dump from the DMA buffer into the user buffer */
|
||||||
|
offset = 0;
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
if (ocs_copy_to_user((uint8_t*)buf + offset,
|
||||||
|
dump_buffers[i].virt, dump_buffers[i].size)) {
|
||||||
|
ocs_log_err(ocs, "ocs_copy_to_user failed\n");
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
offset += dump_buffers[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_and_return:
|
||||||
|
/* Free the DMA buffer and return */
|
||||||
|
for (i = 0; i < num_buffers; i++) {
|
||||||
|
ocs_dma_free(ocs, &dump_buffers[i]);
|
||||||
|
}
|
||||||
|
ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
42
sys/dev/ocs_fc/ocs_gendump.h
Normal file
42
sys/dev/ocs_fc/ocs_gendump.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Broadcom. All rights reserved.
|
||||||
|
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__OCS_GENDUMP_H__)
|
||||||
|
#define __OCS_GENDUMP_H__
|
||||||
|
extern int ocs_gen_dump(ocs_t *ocs);
|
||||||
|
extern int ocs_fdb_dump(ocs_t *ocs);
|
||||||
|
extern int ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen);
|
||||||
|
extern int ocs_function_speciic_dump(ocs_t *ocs, void *buf, uint32_t buflen);
|
||||||
|
|
||||||
|
#define OCS_MAX_HBA_PORTS 4
|
||||||
|
|
||||||
|
#endif // __OCS_GENDUMP_H__
|
@ -60,22 +60,12 @@ ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len, uint8_t *chan
|
|||||||
static int
|
static int
|
||||||
ocs_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
|
ocs_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct ocs_softc *ocs = cdev->si_drv1;
|
|
||||||
|
|
||||||
device_printf(ocs->dev, "%s\n", __func__);
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ocs_close(struct cdev *cdev, int flag, int fmt, struct thread *td)
|
ocs_close(struct cdev *cdev, int flag, int fmt, struct thread *td)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct ocs_softc *ocs = cdev->si_drv1;
|
|
||||||
|
|
||||||
device_printf(ocs->dev, "%s\n", __func__);
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +85,8 @@ __ocs_ioctl_mbox_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ocs_process_sli_config (ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd, ocs_dma_t *dma){
|
ocs_process_sli_config (ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd, ocs_dma_t *dma)
|
||||||
|
{
|
||||||
sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)mcmd->payload;
|
sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)mcmd->payload;
|
||||||
|
|
||||||
if (sli_config->emb) {
|
if (sli_config->emb) {
|
||||||
|
@ -303,18 +303,21 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *name; /*<< Input: name of property to retrieve */
|
uint8_t *name; /*<< Input: name of property to retrieve */
|
||||||
|
uint16_t name_len; /*<< Input: Length of name */
|
||||||
uint8_t *value; /*<< Output: user space buffer in which to place the response */
|
uint8_t *value; /*<< Output: user space buffer in which to place the response */
|
||||||
uint32_t value_length; /*<< Input: size of the user space buffer */
|
uint32_t value_length; /*<< Input: size of the user space buffer */
|
||||||
} ocs_ioctl_cmd_get_t;
|
} ocs_ioctl_cmd_get_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *name; /*<< Input: name of property to set */
|
uint8_t *name; /*<< Input: name of property to set */
|
||||||
|
uint16_t name_len; /*<< Input: Length of name */
|
||||||
uint8_t *value; /*<< Input: user space buffer which contains the new value */
|
uint8_t *value; /*<< Input: user space buffer which contains the new value */
|
||||||
int32_t result; /*<< Output: result */
|
int32_t result; /*<< Output: result */
|
||||||
} ocs_ioctl_cmd_set_t;
|
} ocs_ioctl_cmd_set_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *name; /*<< Input: name of action to execute */
|
uint8_t *name; /*<< Input: name of action to execute */
|
||||||
|
uint16_t name_len; /*<< Input: Length of name */
|
||||||
void *arg_in; /*<< Input: pointer to argument in user space */
|
void *arg_in; /*<< Input: pointer to argument in user space */
|
||||||
uint32_t arg_in_length; /*<< Input: size of arg_in in bytes */
|
uint32_t arg_in_length; /*<< Input: size of arg_in in bytes */
|
||||||
void *arg_out; /*<< Output: pointer to argument from kernel to user */
|
void *arg_out; /*<< Output: pointer to argument from kernel to user */
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "ocs.h"
|
#include "ocs.h"
|
||||||
#include "ocs_mgmt.h"
|
#include "ocs_mgmt.h"
|
||||||
|
#include "ocs_gendump.h"
|
||||||
#include "ocs_vpd.h"
|
#include "ocs_vpd.h"
|
||||||
|
|
||||||
#define SFP_PAGE_SIZE 128
|
#define SFP_PAGE_SIZE 128
|
||||||
@ -55,11 +56,6 @@ static int ocs_mgmt_function_reset(ocs_t *ocs, char *, void *buf, uint32_t buf_l
|
|||||||
static void ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg);
|
static void ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg);
|
||||||
static int ocs_mgmt_force_assert(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
|
static int ocs_mgmt_force_assert(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
|
||||||
|
|
||||||
#if defined(OCS_INCLUDE_RAMD)
|
|
||||||
static int32_t
|
|
||||||
ocs_mgmt_read_phys(ocs_t *ocs, char *, void *, uint32_t , void *, uint32_t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Getters */
|
/* Getters */
|
||||||
|
|
||||||
static void get_nodes_count(ocs_t *, char *, ocs_textbuf_t*);
|
static void get_nodes_count(ocs_t *, char *, ocs_textbuf_t*);
|
||||||
@ -141,9 +137,6 @@ static int set_nv_wwn(ocs_t*, char*, char*);
|
|||||||
static int set_loglevel(ocs_t*, char*, char*);
|
static int set_loglevel(ocs_t*, char*, char*);
|
||||||
|
|
||||||
static void ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg);
|
static void ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg);
|
||||||
#if defined(OCS_INCLUDE_RAMD)
|
|
||||||
static void* find_address_in_target(ocs_ramdisc_t **ramdisc_array, uint32_t ramdisc_count, uintptr_t target_addr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ocs_mgmt_table_entry_t mgmt_table[] = {
|
ocs_mgmt_table_entry_t mgmt_table[] = {
|
||||||
{"nodes_count", get_nodes_count, NULL, NULL},
|
{"nodes_count", get_nodes_count, NULL, NULL},
|
||||||
@ -193,9 +186,6 @@ ocs_mgmt_table_entry_t mgmt_table[] = {
|
|||||||
{"firmware_write", NULL, NULL, ocs_mgmt_firmware_write},
|
{"firmware_write", NULL, NULL, ocs_mgmt_firmware_write},
|
||||||
{"firmware_reset", NULL, NULL, ocs_mgmt_firmware_reset},
|
{"firmware_reset", NULL, NULL, ocs_mgmt_firmware_reset},
|
||||||
{"function_reset", NULL, NULL, ocs_mgmt_function_reset},
|
{"function_reset", NULL, NULL, ocs_mgmt_function_reset},
|
||||||
#if defined(OCS_INCLUDE_RAMD)
|
|
||||||
{"read_phys", NULL, NULL, ocs_mgmt_read_phys},
|
|
||||||
#endif
|
|
||||||
{"force_assert", NULL, NULL, ocs_mgmt_force_assert},
|
{"force_assert", NULL, NULL, ocs_mgmt_force_assert},
|
||||||
|
|
||||||
{"tgt_rscn_delay", get_tgt_rscn_delay, set_tgt_rscn_delay, NULL},
|
{"tgt_rscn_delay", get_tgt_rscn_delay, set_tgt_rscn_delay, NULL},
|
||||||
@ -490,6 +480,15 @@ ocs_mgmt_exec(ocs_t *ocs, char *action, void *arg_in,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See if it's a value I can supply */
|
||||||
|
if (ocs_strcmp(unqualified_name, "driver/gendump") == 0) {
|
||||||
|
return ocs_gen_dump(ocs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ocs_strcmp(unqualified_name, "driver/dump_to_host") == 0) {
|
||||||
|
return ocs_dump_to_host(ocs, arg_out, arg_out_length);
|
||||||
|
}
|
||||||
|
|
||||||
if ((ocs->mgmt_functions) && (ocs->mgmt_functions->exec_handler)) {
|
if ((ocs->mgmt_functions) && (ocs->mgmt_functions->exec_handler)) {
|
||||||
result = ocs->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
|
result = ocs->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
|
||||||
arg_out, arg_out_length, ocs);
|
arg_out, arg_out_length, ocs);
|
||||||
@ -559,137 +558,6 @@ ocs_mgmt_get_all(ocs_t *ocs, ocs_textbuf_t *textbuf)
|
|||||||
ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
|
ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OCS_INCLUDE_RAMD)
|
|
||||||
static int32_t
|
|
||||||
ocs_mgmt_read_phys(ocs_t *ocs, char *name, void *arg_in, uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length)
|
|
||||||
{
|
|
||||||
uint32_t length;
|
|
||||||
char addr_str[80];
|
|
||||||
uintptr_t target_addr;
|
|
||||||
void* vaddr = NULL;
|
|
||||||
ocs_ramdisc_t **ramdisc_array;
|
|
||||||
uint32_t ramdisc_count;
|
|
||||||
|
|
||||||
if ((arg_in == NULL) ||
|
|
||||||
(arg_in_length == 0) ||
|
|
||||||
(arg_out == NULL) ||
|
|
||||||
(arg_out_length == 0)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_in_length > 80) {
|
|
||||||
arg_in_length = 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ocs_copy_from_user(addr_str, arg_in, arg_in_length)) {
|
|
||||||
ocs_log_test(ocs, "Failed to copy addr from user\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_addr = (uintptr_t)ocs_strtoul(addr_str, NULL, 0);
|
|
||||||
/* addr_str must be the physical address of a buffer that was reported
|
|
||||||
* in an SGL. Search ramdiscs looking for a segment that contains that
|
|
||||||
* physical address
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (ocs->tgt_ocs.use_global_ramd) {
|
|
||||||
/* Only one target */
|
|
||||||
ramdisc_count = ocs->tgt_ocs.rdisc_count;
|
|
||||||
ramdisc_array = ocs->tgt_ocs.rdisc;
|
|
||||||
vaddr = find_address_in_target(ramdisc_array, ramdisc_count, target_addr);
|
|
||||||
} else {
|
|
||||||
/* Multiple targets. Each target is on a sport */
|
|
||||||
uint32_t domain_idx;
|
|
||||||
|
|
||||||
for (domain_idx=0; domain_idx<ocs->domain_instance_count; domain_idx++) {
|
|
||||||
ocs_domain_t *domain;
|
|
||||||
uint32_t sport_idx;
|
|
||||||
|
|
||||||
domain = ocs_domain_get_instance(ocs, domain_idx);
|
|
||||||
for (sport_idx=0; sport_idx < domain->sport_instance_count; sport_idx++) {
|
|
||||||
ocs_sport_t *sport;
|
|
||||||
|
|
||||||
sport = ocs_sport_get_instance(domain, sport_idx);
|
|
||||||
ramdisc_count = sport->tgt_sport.rdisc_count;
|
|
||||||
ramdisc_array = sport->tgt_sport.rdisc;
|
|
||||||
vaddr = find_address_in_target(ramdisc_array, ramdisc_count, target_addr);
|
|
||||||
|
|
||||||
if (vaddr != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
length = arg_out_length;
|
|
||||||
|
|
||||||
if (vaddr != NULL) {
|
|
||||||
if (ocs_copy_to_user(arg_out, vaddr, length)) {
|
|
||||||
ocs_log_test(ocs, "Failed to copy buffer to user\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function searches a target for a given physical address.
|
|
||||||
* The target is made up of a number of LUNs, each represented by
|
|
||||||
* a ocs_ramdisc_t.
|
|
||||||
*/
|
|
||||||
static void* find_address_in_target(ocs_ramdisc_t **ramdisc_array, uint32_t ramdisc_count, uintptr_t target_addr)
|
|
||||||
{
|
|
||||||
void *vaddr = NULL;
|
|
||||||
uint32_t ramdisc_idx;
|
|
||||||
|
|
||||||
/* Check each ramdisc */
|
|
||||||
for (ramdisc_idx=0; ramdisc_idx<ramdisc_count; ramdisc_idx++) {
|
|
||||||
uint32_t segment_idx;
|
|
||||||
ocs_ramdisc_t *rdisc;
|
|
||||||
rdisc = ramdisc_array[ramdisc_idx];
|
|
||||||
/* Check each segment in the ramdisc */
|
|
||||||
for (segment_idx=0; segment_idx<rdisc->segment_count; segment_idx++) {
|
|
||||||
ramdisc_segment_t *segment = rdisc->segments[segment_idx];
|
|
||||||
uintptr_t segment_start;
|
|
||||||
uintptr_t segment_end;
|
|
||||||
uint32_t offset;
|
|
||||||
|
|
||||||
segment_start = segment->data_segment.phys;
|
|
||||||
segment_end = segment->data_segment.phys + segment->data_segment.size - 1;
|
|
||||||
if ((target_addr >= segment_start) && (target_addr <= segment_end)) {
|
|
||||||
/* Found the target address */
|
|
||||||
offset = target_addr - segment_start;
|
|
||||||
vaddr = (uint32_t*)segment->data_segment.virt + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdisc->dif_separate) {
|
|
||||||
segment_start = segment->dif_segment.phys;
|
|
||||||
segment_end = segment->data_segment.phys + segment->dif_segment.size - 1;
|
|
||||||
if ((target_addr >= segment_start) && (target_addr <= segment_end)) {
|
|
||||||
/* Found the target address */
|
|
||||||
offset = target_addr - segment_start;
|
|
||||||
vaddr = (uint32_t*)segment->dif_segment.virt + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vaddr != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vaddr != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vaddr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
ocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
|
ocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
|
||||||
{
|
{
|
||||||
|
@ -883,13 +883,12 @@ ocs_pci_model(uint16_t vendor, uint16_t device)
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
void
|
||||||
ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
|
ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
|
||||||
{
|
{
|
||||||
*bus = pci_get_bus(ocs->dev);
|
*bus = pci_get_bus(ocs->dev);
|
||||||
*dev = pci_get_slot(ocs->dev);
|
*dev = pci_get_slot(ocs->dev);
|
||||||
*func= pci_get_function(ocs->dev);
|
*func= pci_get_function(ocs->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1050,9 +1050,8 @@ typedef struct ocs_pci_reg_s {
|
|||||||
* @param dev Pointer to location to store the device number.
|
* @param dev Pointer to location to store the device number.
|
||||||
* @param func Pointer to location to store the function number.
|
* @param func Pointer to location to store the function number.
|
||||||
*
|
*
|
||||||
* @return Returns 0.
|
|
||||||
*/
|
*/
|
||||||
extern int32_t
|
extern void
|
||||||
ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
|
ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
|
||||||
|
|
||||||
extern ocs_t *ocs_get_instance(uint32_t index);
|
extern ocs_t *ocs_get_instance(uint32_t index);
|
||||||
|
@ -33,7 +33,8 @@ SRCS += \
|
|||||||
ocs_scsi.c \
|
ocs_scsi.c \
|
||||||
ocs_unsol.c \
|
ocs_unsol.c \
|
||||||
ocs_ddump.c \
|
ocs_ddump.c \
|
||||||
ocs_mgmt.c
|
ocs_mgmt.c \
|
||||||
|
ocs_gendump.c
|
||||||
|
|
||||||
|
|
||||||
# CAM initiator/target
|
# CAM initiator/target
|
||||||
|
Loading…
Reference in New Issue
Block a user