git: 44a78c21df4c - stable/13 - ocs_fc: Add gendump and dump_to_host ioctl command support.

From: Ram Kishore Vegesna <ram_at_FreeBSD.org>
Date: Fri, 17 Dec 2021 10:37:09 UTC
The branch stable/13 has been updated by ram:

URL: https://cgit.FreeBSD.org/src/commit/?id=44a78c21df4c344f24e5f6dc3c6010a87c330644

commit 44a78c21df4c344f24e5f6dc3c6010a87c330644
Author:     Ram Kishore Vegesna <ram@FreeBSD.org>
AuthorDate: 2021-06-24 07:05:00 +0000
Commit:     Ram Kishore Vegesna <ram@FreeBSD.org>
CommitDate: 2021-12-17 10:30:59 +0000

    ocs_fc: Add gendump and dump_to_host ioctl command support.
    
    Support to generate firmware dump.
    
    Approved by: mav(mentor)
    
    (cherry picked from commit 29e2dbd42c3e2e10e606b3414f4d0c53021d4e86)
    
    Add ocs_gendump.c to the build, missed in 29e2dbd42c3e.
    
    (cherry picked from commit d0732fa81963d336099a6b134a1eb4be867bfa8b)
---
 sys/conf/files               |   1 +
 sys/dev/ocs_fc/ocs_gendump.c | 388 +++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ocs_fc/ocs_gendump.h |  42 +++++
 sys/dev/ocs_fc/ocs_ioctl.c   |  13 +-
 sys/dev/ocs_fc/ocs_ioctl.h   |   3 +
 sys/dev/ocs_fc/ocs_mgmt.c    | 152 ++---------------
 sys/dev/ocs_fc/ocs_os.c      |   3 +-
 sys/dev/ocs_fc/ocs_os.h      |   3 +-
 sys/modules/ocs_fc/Makefile  |   3 +-
 9 files changed, 450 insertions(+), 158 deletions(-)

diff --git a/sys/conf/files b/sys/conf/files
index abfc1f9101ae..6b78b509f8ad 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2603,6 +2603,7 @@ dev/oce/oce_mbox.c		optional oce pci
 dev/oce/oce_queue.c		optional oce pci
 dev/oce/oce_sysctl.c		optional oce pci
 dev/oce/oce_util.c		optional oce pci
+dev/ocs_fc/ocs_gendump.c	optional ocs_fc pci
 dev/ocs_fc/ocs_pci.c		optional ocs_fc pci
 dev/ocs_fc/ocs_ioctl.c		optional ocs_fc pci
 dev/ocs_fc/ocs_os.c		optional ocs_fc pci
diff --git a/sys/dev/ocs_fc/ocs_gendump.c b/sys/dev/ocs_fc/ocs_gendump.c
new file mode 100644
index 000000000000..d24870f39668
--- /dev/null
+++ b/sys/dev/ocs_fc/ocs_gendump.c
@@ -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;
+
+}
diff --git a/sys/dev/ocs_fc/ocs_gendump.h b/sys/dev/ocs_fc/ocs_gendump.h
new file mode 100644
index 000000000000..2343003feef6
--- /dev/null
+++ b/sys/dev/ocs_fc/ocs_gendump.h
@@ -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__
diff --git a/sys/dev/ocs_fc/ocs_ioctl.c b/sys/dev/ocs_fc/ocs_ioctl.c
index 13d80bd3edde..c0576bd6600f 100644
--- a/sys/dev/ocs_fc/ocs_ioctl.c
+++ b/sys/dev/ocs_fc/ocs_ioctl.c
@@ -60,22 +60,12 @@ ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len, uint8_t *chan
 static int
 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;
 }
 
 static int
 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;
 }
 
@@ -95,7 +85,8 @@ __ocs_ioctl_mbox_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 }
 
 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;
 
 	if (sli_config->emb) {
diff --git a/sys/dev/ocs_fc/ocs_ioctl.h b/sys/dev/ocs_fc/ocs_ioctl.h
index ad2460d09b87..f2a291843d5a 100644
--- a/sys/dev/ocs_fc/ocs_ioctl.h
+++ b/sys/dev/ocs_fc/ocs_ioctl.h
@@ -303,18 +303,21 @@ typedef struct {
 
 typedef struct {
 	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 */
 	uint32_t	value_length;		/*<< Input: size of the user space buffer */
 } ocs_ioctl_cmd_get_t;
 
 typedef struct {
 	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 */
 	int32_t		result;			/*<< Output: result */
 } ocs_ioctl_cmd_set_t;
 
 typedef struct {
 	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 */
 	uint32_t	arg_in_length;		/*<< Input: size of arg_in in bytes */
 	void		*arg_out;		/*<< Output: pointer to argument from kernel to user */
diff --git a/sys/dev/ocs_fc/ocs_mgmt.c b/sys/dev/ocs_fc/ocs_mgmt.c
index 1f22a0316791..ff0e028caea2 100644
--- a/sys/dev/ocs_fc/ocs_mgmt.c
+++ b/sys/dev/ocs_fc/ocs_mgmt.c
@@ -42,6 +42,7 @@
 
 #include "ocs.h"
 #include "ocs_mgmt.h"
+#include "ocs_gendump.h"
 #include "ocs_vpd.h"
 
 #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 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 */
 
 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 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[] = {
 		{"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_reset", NULL, NULL, ocs_mgmt_firmware_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},
 
 		{"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)) {
 			result = ocs->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
 								   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");
 }
 
-#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
 ocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
 {
diff --git a/sys/dev/ocs_fc/ocs_os.c b/sys/dev/ocs_fc/ocs_os.c
index 985a611ba91e..4e4edea2e63f 100644
--- a/sys/dev/ocs_fc/ocs_os.c
+++ b/sys/dev/ocs_fc/ocs_os.c
@@ -883,13 +883,12 @@ ocs_pci_model(uint16_t vendor, uint16_t device)
 	return "unknown";
 }
 
-int32_t
+void
 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
 {
 	*bus = pci_get_bus(ocs->dev);
 	*dev = pci_get_slot(ocs->dev);
 	*func= pci_get_function(ocs->dev);
-	return 0;
 }
 
 /**
diff --git a/sys/dev/ocs_fc/ocs_os.h b/sys/dev/ocs_fc/ocs_os.h
index a7ad51257641..9ab3be96ec2e 100644
--- a/sys/dev/ocs_fc/ocs_os.h
+++ b/sys/dev/ocs_fc/ocs_os.h
@@ -1050,9 +1050,8 @@ typedef struct ocs_pci_reg_s {
  * @param dev Pointer to location to store the device 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);
 
 extern ocs_t *ocs_get_instance(uint32_t index);
diff --git a/sys/modules/ocs_fc/Makefile b/sys/modules/ocs_fc/Makefile
index 9bab50eba5bc..8d546f9eabfd 100644
--- a/sys/modules/ocs_fc/Makefile
+++ b/sys/modules/ocs_fc/Makefile
@@ -33,7 +33,8 @@ SRCS += \
 	ocs_scsi.c \
 	ocs_unsol.c \
 	ocs_ddump.c \
-	ocs_mgmt.c 
+	ocs_mgmt.c \
+	ocs_gendump.c
 
 
 # CAM initiator/target