xref: /freebsd/sys/dev/ocs_fc/ocs_gendump.c (revision 29e2dbd42c3e2e10e606b3414f4d0c53021d4e86)
1*29e2dbd4SRam Kishore Vegesna /*
2*29e2dbd4SRam Kishore Vegesna  * Copyright (c) 2021 Broadcom. All rights reserved.
3*29e2dbd4SRam Kishore Vegesna  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4*29e2dbd4SRam Kishore Vegesna  *
5*29e2dbd4SRam Kishore Vegesna  * Redistribution and use in source and binary forms, with or without
6*29e2dbd4SRam Kishore Vegesna  * modification, are permitted provided that the following conditions are met:
7*29e2dbd4SRam Kishore Vegesna  *
8*29e2dbd4SRam Kishore Vegesna  * 1. Redistributions of source code must retain the above copyright notice,
9*29e2dbd4SRam Kishore Vegesna  *    this list of conditions and the following disclaimer.
10*29e2dbd4SRam Kishore Vegesna  *
11*29e2dbd4SRam Kishore Vegesna  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*29e2dbd4SRam Kishore Vegesna  *    this list of conditions and the following disclaimer in the documentation
13*29e2dbd4SRam Kishore Vegesna  *    and/or other materials provided with the distribution.
14*29e2dbd4SRam Kishore Vegesna  *
15*29e2dbd4SRam Kishore Vegesna  * 3. Neither the name of the copyright holder nor the names of its contributors
16*29e2dbd4SRam Kishore Vegesna  *    may be used to endorse or promote products derived from this software
17*29e2dbd4SRam Kishore Vegesna  *    without specific prior written permission.
18*29e2dbd4SRam Kishore Vegesna  *
19*29e2dbd4SRam Kishore Vegesna  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*29e2dbd4SRam Kishore Vegesna  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*29e2dbd4SRam Kishore Vegesna  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*29e2dbd4SRam Kishore Vegesna  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23*29e2dbd4SRam Kishore Vegesna  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*29e2dbd4SRam Kishore Vegesna  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*29e2dbd4SRam Kishore Vegesna  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*29e2dbd4SRam Kishore Vegesna  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*29e2dbd4SRam Kishore Vegesna  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*29e2dbd4SRam Kishore Vegesna  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*29e2dbd4SRam Kishore Vegesna  * POSSIBILITY OF SUCH DAMAGE.
30*29e2dbd4SRam Kishore Vegesna  *
31*29e2dbd4SRam Kishore Vegesna  */
32*29e2dbd4SRam Kishore Vegesna 
33*29e2dbd4SRam Kishore Vegesna #include "ocs.h"
34*29e2dbd4SRam Kishore Vegesna #include "ocs_gendump.h"
35*29e2dbd4SRam Kishore Vegesna 
36*29e2dbd4SRam Kishore Vegesna /* Reset all the functions associated with a bus/dev */
37*29e2dbd4SRam Kishore Vegesna static int
38*29e2dbd4SRam Kishore Vegesna ocs_gen_dump_reset(uint8_t bus, uint8_t dev)
39*29e2dbd4SRam Kishore Vegesna {
40*29e2dbd4SRam Kishore Vegesna 	uint32_t index = 0;
41*29e2dbd4SRam Kishore Vegesna 	ocs_t *ocs;
42*29e2dbd4SRam Kishore Vegesna 	int rc = 0;
43*29e2dbd4SRam Kishore Vegesna 
44*29e2dbd4SRam Kishore Vegesna 	while ((ocs = ocs_get_instance(index++)) != NULL) {
45*29e2dbd4SRam Kishore Vegesna 		uint8_t ocs_bus, ocs_dev, ocs_func;
46*29e2dbd4SRam Kishore Vegesna 		ocs_domain_t *domain;
47*29e2dbd4SRam Kishore Vegesna 
48*29e2dbd4SRam Kishore Vegesna 		ocs_get_bus_dev_func(ocs, &ocs_bus, &ocs_dev, &ocs_func);
49*29e2dbd4SRam Kishore Vegesna 
50*29e2dbd4SRam Kishore Vegesna 		if (!(ocs_bus == bus && ocs_dev == dev))
51*29e2dbd4SRam Kishore Vegesna 			continue;
52*29e2dbd4SRam Kishore Vegesna 
53*29e2dbd4SRam Kishore Vegesna 		if (ocs_hw_reset(&ocs->hw, OCS_HW_RESET_FUNCTION)) {
54*29e2dbd4SRam Kishore Vegesna 			ocs_log_test(ocs, "failed to reset port\n");
55*29e2dbd4SRam Kishore Vegesna 			rc = -1;
56*29e2dbd4SRam Kishore Vegesna 			continue;
57*29e2dbd4SRam Kishore Vegesna 		}
58*29e2dbd4SRam Kishore Vegesna 
59*29e2dbd4SRam Kishore Vegesna 		ocs_log_debug(ocs, "successfully reset port\n");
60*29e2dbd4SRam Kishore Vegesna 		while ((domain = ocs_list_get_head(&ocs->domain_list)) != NULL) {
61*29e2dbd4SRam Kishore Vegesna 			ocs_log_debug(ocs, "free domain %p\n", domain);
62*29e2dbd4SRam Kishore Vegesna 			ocs_domain_force_free(domain);
63*29e2dbd4SRam Kishore Vegesna 		}
64*29e2dbd4SRam Kishore Vegesna 		/* now initialize hw so user can read the dump in */
65*29e2dbd4SRam Kishore Vegesna 		if (ocs_hw_init(&ocs->hw)) {
66*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(ocs, "failed to initialize hw\n");
67*29e2dbd4SRam Kishore Vegesna 			rc = -1;
68*29e2dbd4SRam Kishore Vegesna 		} else {
69*29e2dbd4SRam Kishore Vegesna 			ocs_log_debug(ocs, "successfully initialized hw\n");
70*29e2dbd4SRam Kishore Vegesna 		}
71*29e2dbd4SRam Kishore Vegesna 	}
72*29e2dbd4SRam Kishore Vegesna 	return rc;
73*29e2dbd4SRam Kishore Vegesna }
74*29e2dbd4SRam Kishore Vegesna 
75*29e2dbd4SRam Kishore Vegesna int
76*29e2dbd4SRam Kishore Vegesna ocs_gen_dump(ocs_t *ocs)
77*29e2dbd4SRam Kishore Vegesna {
78*29e2dbd4SRam Kishore Vegesna 	uint32_t reset_required;
79*29e2dbd4SRam Kishore Vegesna 	uint32_t dump_ready;
80*29e2dbd4SRam Kishore Vegesna 	uint32_t ms_waited;
81*29e2dbd4SRam Kishore Vegesna 	uint8_t bus, dev, func;
82*29e2dbd4SRam Kishore Vegesna 	int rc = 0;
83*29e2dbd4SRam Kishore Vegesna 	int index = 0, port_index = 0;
84*29e2dbd4SRam Kishore Vegesna 	ocs_t *nxt_ocs;
85*29e2dbd4SRam Kishore Vegesna 	uint8_t nxt_bus, nxt_dev, nxt_func;
86*29e2dbd4SRam Kishore Vegesna 	uint8_t prev_port_state[OCS_MAX_HBA_PORTS] = {0,};
87*29e2dbd4SRam Kishore Vegesna 	ocs_xport_stats_t link_status;
88*29e2dbd4SRam Kishore Vegesna 
89*29e2dbd4SRam Kishore Vegesna 	ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
90*29e2dbd4SRam Kishore Vegesna 
91*29e2dbd4SRam Kishore Vegesna 	/* Drop link on all ports belongs to this HBA*/
92*29e2dbd4SRam Kishore Vegesna 	while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
93*29e2dbd4SRam Kishore Vegesna 		ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
94*29e2dbd4SRam Kishore Vegesna 
95*29e2dbd4SRam Kishore Vegesna 		if (!(bus == nxt_bus && dev == nxt_dev))
96*29e2dbd4SRam Kishore Vegesna 			continue;
97*29e2dbd4SRam Kishore Vegesna 
98*29e2dbd4SRam Kishore Vegesna 		if ((port_index >= OCS_MAX_HBA_PORTS))
99*29e2dbd4SRam Kishore Vegesna 			continue;
100*29e2dbd4SRam Kishore Vegesna 
101*29e2dbd4SRam Kishore Vegesna 		/* Check current link status and save for future use */
102*29e2dbd4SRam Kishore Vegesna 		if (ocs_xport_status(nxt_ocs->xport, OCS_XPORT_PORT_STATUS,
103*29e2dbd4SRam Kishore Vegesna 		   &link_status) == 0) {
104*29e2dbd4SRam Kishore Vegesna 			if (link_status.value == OCS_XPORT_PORT_ONLINE) {
105*29e2dbd4SRam Kishore Vegesna 				prev_port_state[port_index] = 1;
106*29e2dbd4SRam Kishore Vegesna 				ocs_xport_control(nxt_ocs->xport,
107*29e2dbd4SRam Kishore Vegesna 						  OCS_XPORT_PORT_OFFLINE);
108*29e2dbd4SRam Kishore Vegesna 			} else {
109*29e2dbd4SRam Kishore Vegesna 				prev_port_state[port_index] = 0;
110*29e2dbd4SRam Kishore Vegesna 			}
111*29e2dbd4SRam Kishore Vegesna 		}
112*29e2dbd4SRam Kishore Vegesna 		port_index++;
113*29e2dbd4SRam Kishore Vegesna 	}
114*29e2dbd4SRam Kishore Vegesna 
115*29e2dbd4SRam Kishore Vegesna 	/* Wait until all ports have quiesced */
116*29e2dbd4SRam Kishore Vegesna 	for (index = 0; (nxt_ocs = ocs_get_instance(index++)) != NULL; ) {
117*29e2dbd4SRam Kishore Vegesna 		ms_waited = 0;
118*29e2dbd4SRam Kishore Vegesna 		for (;;) {
119*29e2dbd4SRam Kishore Vegesna 			ocs_xport_stats_t status;
120*29e2dbd4SRam Kishore Vegesna 
121*29e2dbd4SRam Kishore Vegesna 			ocs_xport_status(nxt_ocs->xport, OCS_XPORT_IS_QUIESCED,
122*29e2dbd4SRam Kishore Vegesna 					 &status);
123*29e2dbd4SRam Kishore Vegesna 			if (status.value) {
124*29e2dbd4SRam Kishore Vegesna 				ocs_log_debug(nxt_ocs, "port quiesced\n");
125*29e2dbd4SRam Kishore Vegesna 				break;
126*29e2dbd4SRam Kishore Vegesna 			}
127*29e2dbd4SRam Kishore Vegesna 
128*29e2dbd4SRam Kishore Vegesna 			ocs_msleep(10);
129*29e2dbd4SRam Kishore Vegesna 			ms_waited += 10;
130*29e2dbd4SRam Kishore Vegesna 			if (ms_waited > 60000) {
131*29e2dbd4SRam Kishore Vegesna 				ocs_log_test(nxt_ocs,
132*29e2dbd4SRam Kishore Vegesna 				    "timed out waiting for port to quiesce\n");
133*29e2dbd4SRam Kishore Vegesna 				break;
134*29e2dbd4SRam Kishore Vegesna 			}
135*29e2dbd4SRam Kishore Vegesna 		}
136*29e2dbd4SRam Kishore Vegesna 	}
137*29e2dbd4SRam Kishore Vegesna 
138*29e2dbd4SRam Kishore Vegesna 	/* Initiate dump */
139*29e2dbd4SRam Kishore Vegesna 	if (ocs_hw_raise_ue(&ocs->hw, 1) == OCS_HW_RTN_SUCCESS) {
140*29e2dbd4SRam Kishore Vegesna 
141*29e2dbd4SRam Kishore Vegesna 		/* Wait for dump to complete */
142*29e2dbd4SRam Kishore Vegesna 		ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
143*29e2dbd4SRam Kishore Vegesna 
144*29e2dbd4SRam Kishore Vegesna 		dump_ready = 0;
145*29e2dbd4SRam Kishore Vegesna 		ms_waited = 0;
146*29e2dbd4SRam Kishore Vegesna 		while ((!dump_ready) && (ms_waited < 30000)) {
147*29e2dbd4SRam Kishore Vegesna 			ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
148*29e2dbd4SRam Kishore Vegesna 			ocs_udelay(10000);
149*29e2dbd4SRam Kishore Vegesna 			ms_waited += 10;
150*29e2dbd4SRam Kishore Vegesna 		}
151*29e2dbd4SRam Kishore Vegesna 
152*29e2dbd4SRam Kishore Vegesna 		if (!dump_ready) {
153*29e2dbd4SRam Kishore Vegesna 			ocs_log_test(ocs, "Failed to see dump after 30 secs\n");
154*29e2dbd4SRam Kishore Vegesna 			rc = -1;
155*29e2dbd4SRam Kishore Vegesna 		} else {
156*29e2dbd4SRam Kishore Vegesna 			ocs_log_debug(ocs, "sucessfully generated dump\n");
157*29e2dbd4SRam Kishore Vegesna 		}
158*29e2dbd4SRam Kishore Vegesna 
159*29e2dbd4SRam Kishore Vegesna 		/* now reset port */
160*29e2dbd4SRam Kishore Vegesna 		ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required);
161*29e2dbd4SRam Kishore Vegesna 		ocs_log_debug(ocs, "reset required=%d\n", reset_required);
162*29e2dbd4SRam Kishore Vegesna 		if (reset_required) {
163*29e2dbd4SRam Kishore Vegesna 			if (ocs_gen_dump_reset(bus, dev) == 0) {
164*29e2dbd4SRam Kishore Vegesna 				ocs_log_debug(ocs, "all devices reset\n");
165*29e2dbd4SRam Kishore Vegesna 			} else {
166*29e2dbd4SRam Kishore Vegesna 				ocs_log_test(ocs, "all devices NOT reset\n");
167*29e2dbd4SRam Kishore Vegesna 			}
168*29e2dbd4SRam Kishore Vegesna 		}
169*29e2dbd4SRam Kishore Vegesna 	} else {
170*29e2dbd4SRam Kishore Vegesna 		ocs_log_test(ocs, "dump request to hw failed\n");
171*29e2dbd4SRam Kishore Vegesna 		rc = -1;
172*29e2dbd4SRam Kishore Vegesna 	}
173*29e2dbd4SRam Kishore Vegesna 
174*29e2dbd4SRam Kishore Vegesna 	index = port_index = 0;
175*29e2dbd4SRam Kishore Vegesna 	nxt_ocs = NULL;
176*29e2dbd4SRam Kishore Vegesna 	/* Bring links on each HBA port to previous state*/
177*29e2dbd4SRam Kishore Vegesna 	while ((nxt_ocs = ocs_get_instance(index++)) != NULL) {
178*29e2dbd4SRam Kishore Vegesna 		ocs_get_bus_dev_func(nxt_ocs, &nxt_bus, &nxt_dev, &nxt_func);
179*29e2dbd4SRam Kishore Vegesna 		if (port_index > OCS_MAX_HBA_PORTS) {
180*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(NULL, "port index(%d) out of boundary\n",
181*29e2dbd4SRam Kishore Vegesna 				    port_index);
182*29e2dbd4SRam Kishore Vegesna 			rc = -1;
183*29e2dbd4SRam Kishore Vegesna 			break;
184*29e2dbd4SRam Kishore Vegesna 		}
185*29e2dbd4SRam Kishore Vegesna 		if ((bus == nxt_bus) && (dev == nxt_dev) &&
186*29e2dbd4SRam Kishore Vegesna 		    prev_port_state[port_index++]) {
187*29e2dbd4SRam Kishore Vegesna 			ocs_xport_control(nxt_ocs->xport, OCS_XPORT_PORT_ONLINE);
188*29e2dbd4SRam Kishore Vegesna 		}
189*29e2dbd4SRam Kishore Vegesna 	}
190*29e2dbd4SRam Kishore Vegesna 
191*29e2dbd4SRam Kishore Vegesna 	return rc;
192*29e2dbd4SRam Kishore Vegesna }
193*29e2dbd4SRam Kishore Vegesna 
194*29e2dbd4SRam Kishore Vegesna int
195*29e2dbd4SRam Kishore Vegesna ocs_fdb_dump(ocs_t *ocs)
196*29e2dbd4SRam Kishore Vegesna {
197*29e2dbd4SRam Kishore Vegesna 	uint32_t dump_ready;
198*29e2dbd4SRam Kishore Vegesna 	uint32_t ms_waited;
199*29e2dbd4SRam Kishore Vegesna 	int rc = 0;
200*29e2dbd4SRam Kishore Vegesna 
201*29e2dbd4SRam Kishore Vegesna #define FDB 2
202*29e2dbd4SRam Kishore Vegesna 
203*29e2dbd4SRam Kishore Vegesna 	/* Initiate dump */
204*29e2dbd4SRam Kishore Vegesna 	if (ocs_hw_raise_ue(&ocs->hw, FDB) == OCS_HW_RTN_SUCCESS) {
205*29e2dbd4SRam Kishore Vegesna 
206*29e2dbd4SRam Kishore Vegesna 		/* Wait for dump to complete */
207*29e2dbd4SRam Kishore Vegesna 		ocs_log_debug(ocs, "Dump requested, wait for completion.\n");
208*29e2dbd4SRam Kishore Vegesna 
209*29e2dbd4SRam Kishore Vegesna 		dump_ready = 0;
210*29e2dbd4SRam Kishore Vegesna 		ms_waited = 0;
211*29e2dbd4SRam Kishore Vegesna 		while ((!(dump_ready == FDB)) && (ms_waited < 10000)) {
212*29e2dbd4SRam Kishore Vegesna 			ocs_hw_get(&ocs->hw, OCS_HW_DUMP_READY, &dump_ready);
213*29e2dbd4SRam Kishore Vegesna 			ocs_udelay(10000);
214*29e2dbd4SRam Kishore Vegesna 			ms_waited += 10;
215*29e2dbd4SRam Kishore Vegesna 		}
216*29e2dbd4SRam Kishore Vegesna 
217*29e2dbd4SRam Kishore Vegesna 		if (!dump_ready) {
218*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(ocs, "Failed to see dump after 10 secs\n");
219*29e2dbd4SRam Kishore Vegesna 			return -1;
220*29e2dbd4SRam Kishore Vegesna 		}
221*29e2dbd4SRam Kishore Vegesna 
222*29e2dbd4SRam Kishore Vegesna 		ocs_log_debug(ocs, "sucessfully generated dump\n");
223*29e2dbd4SRam Kishore Vegesna 
224*29e2dbd4SRam Kishore Vegesna 	} else {
225*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "dump request to hw failed\n");
226*29e2dbd4SRam Kishore Vegesna 		rc = -1;
227*29e2dbd4SRam Kishore Vegesna 	}
228*29e2dbd4SRam Kishore Vegesna 
229*29e2dbd4SRam Kishore Vegesna 	return rc;
230*29e2dbd4SRam Kishore Vegesna }
231*29e2dbd4SRam Kishore Vegesna 
232*29e2dbd4SRam Kishore Vegesna /**
233*29e2dbd4SRam Kishore Vegesna  * @brief Create a Lancer dump into a memory buffer
234*29e2dbd4SRam Kishore Vegesna  * @par Description
235*29e2dbd4SRam Kishore Vegesna  * This function creates a DMA buffer to hold a Lancer dump,
236*29e2dbd4SRam Kishore Vegesna  * sets the dump location to point to that buffer, then calls
237*29e2dbd4SRam Kishore Vegesna  * ocs_gen_dump to cause a dump to be transfered to the buffer.
238*29e2dbd4SRam Kishore Vegesna  * After the dump is complete it copies the dump to the provided
239*29e2dbd4SRam Kishore Vegesna  * user space buffer.
240*29e2dbd4SRam Kishore Vegesna  *
241*29e2dbd4SRam Kishore Vegesna  * @param ocs Pointer to ocs structure
242*29e2dbd4SRam Kishore Vegesna  * @param buf User space buffer in which to store the dump
243*29e2dbd4SRam Kishore Vegesna  * @param buflen Length of the user buffer in bytes
244*29e2dbd4SRam Kishore Vegesna  *
245*29e2dbd4SRam Kishore Vegesna  * @return Returns 0 on success, non-zero on error.
246*29e2dbd4SRam Kishore Vegesna  */
247*29e2dbd4SRam Kishore Vegesna int
248*29e2dbd4SRam Kishore Vegesna ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen)
249*29e2dbd4SRam Kishore Vegesna {
250*29e2dbd4SRam Kishore Vegesna 	int rc;
251*29e2dbd4SRam Kishore Vegesna 	uint32_t i, num_buffers;
252*29e2dbd4SRam Kishore Vegesna 	ocs_dma_t *dump_buffers;
253*29e2dbd4SRam Kishore Vegesna 	uint32_t rem_bytes, offset;
254*29e2dbd4SRam Kishore Vegesna 
255*29e2dbd4SRam Kishore Vegesna 	if (buflen == 0) {
256*29e2dbd4SRam Kishore Vegesna 		ocs_log_test(ocs, "zero buffer length is invalid\n");
257*29e2dbd4SRam Kishore Vegesna 		return -1;
258*29e2dbd4SRam Kishore Vegesna 	}
259*29e2dbd4SRam Kishore Vegesna 
260*29e2dbd4SRam Kishore Vegesna 	num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
261*29e2dbd4SRam Kishore Vegesna 
262*29e2dbd4SRam Kishore Vegesna 	dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
263*29e2dbd4SRam Kishore Vegesna 				  OCS_M_ZERO | OCS_M_NOWAIT);
264*29e2dbd4SRam Kishore Vegesna 	if (dump_buffers == NULL) {
265*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "Failed to dump buffers\n");
266*29e2dbd4SRam Kishore Vegesna 		return -1;
267*29e2dbd4SRam Kishore Vegesna 	}
268*29e2dbd4SRam Kishore Vegesna 
269*29e2dbd4SRam Kishore Vegesna 	/* Allocate a DMA buffers to hold the dump */
270*29e2dbd4SRam Kishore Vegesna 	rem_bytes = buflen;
271*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
272*29e2dbd4SRam Kishore Vegesna 		uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
273*29e2dbd4SRam Kishore Vegesna 
274*29e2dbd4SRam Kishore Vegesna 		rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
275*29e2dbd4SRam Kishore Vegesna 				   OCS_MIN_DMA_ALIGNMENT);
276*29e2dbd4SRam Kishore Vegesna 		if (rc) {
277*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(ocs, "Failed to allocate dump buffer\n");
278*29e2dbd4SRam Kishore Vegesna 
279*29e2dbd4SRam Kishore Vegesna 			/* Free any previously allocated buffers */
280*29e2dbd4SRam Kishore Vegesna 			goto free_and_return;
281*29e2dbd4SRam Kishore Vegesna 		}
282*29e2dbd4SRam Kishore Vegesna 		rem_bytes -= num_bytes;
283*29e2dbd4SRam Kishore Vegesna 	}
284*29e2dbd4SRam Kishore Vegesna 
285*29e2dbd4SRam Kishore Vegesna 	rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 0);
286*29e2dbd4SRam Kishore Vegesna 	if (rc) {
287*29e2dbd4SRam Kishore Vegesna 		ocs_log_test(ocs, "ocs_hw_set_dump_location failed\n");
288*29e2dbd4SRam Kishore Vegesna 		goto free_and_return;
289*29e2dbd4SRam Kishore Vegesna 	}
290*29e2dbd4SRam Kishore Vegesna 
291*29e2dbd4SRam Kishore Vegesna 	/* Generate the dump */
292*29e2dbd4SRam Kishore Vegesna 	rc = ocs_gen_dump(ocs);
293*29e2dbd4SRam Kishore Vegesna 	if (rc) {
294*29e2dbd4SRam Kishore Vegesna 		ocs_log_test(ocs, "ocs_gen_dump failed\n");
295*29e2dbd4SRam Kishore Vegesna 		goto free_and_return;
296*29e2dbd4SRam Kishore Vegesna 	}
297*29e2dbd4SRam Kishore Vegesna 
298*29e2dbd4SRam Kishore Vegesna 	/* Copy the dump from the DMA buffer into the user buffer */
299*29e2dbd4SRam Kishore Vegesna 	offset = 0;
300*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
301*29e2dbd4SRam Kishore Vegesna 		if (ocs_copy_to_user((uint8_t*)buf + offset,
302*29e2dbd4SRam Kishore Vegesna 		    dump_buffers[i].virt, dump_buffers[i].size)) {
303*29e2dbd4SRam Kishore Vegesna 			ocs_log_test(ocs, "ocs_copy_to_user failed\n");
304*29e2dbd4SRam Kishore Vegesna 			rc = -1;
305*29e2dbd4SRam Kishore Vegesna 		}
306*29e2dbd4SRam Kishore Vegesna 		offset += dump_buffers[i].size;
307*29e2dbd4SRam Kishore Vegesna 	}
308*29e2dbd4SRam Kishore Vegesna 
309*29e2dbd4SRam Kishore Vegesna free_and_return:
310*29e2dbd4SRam Kishore Vegesna 	/* Free the DMA buffer and return */
311*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
312*29e2dbd4SRam Kishore Vegesna 		ocs_dma_free(ocs, &dump_buffers[i]);
313*29e2dbd4SRam Kishore Vegesna 	}
314*29e2dbd4SRam Kishore Vegesna 	ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
315*29e2dbd4SRam Kishore Vegesna 	return rc;
316*29e2dbd4SRam Kishore Vegesna }
317*29e2dbd4SRam Kishore Vegesna 
318*29e2dbd4SRam Kishore Vegesna int
319*29e2dbd4SRam Kishore Vegesna ocs_function_speciic_dump(ocs_t *ocs, void *buf, uint32_t buflen)
320*29e2dbd4SRam Kishore Vegesna {
321*29e2dbd4SRam Kishore Vegesna 	int rc;
322*29e2dbd4SRam Kishore Vegesna 	uint32_t i, num_buffers;
323*29e2dbd4SRam Kishore Vegesna 	ocs_dma_t *dump_buffers;
324*29e2dbd4SRam Kishore Vegesna 	uint32_t rem_bytes, offset;
325*29e2dbd4SRam Kishore Vegesna 
326*29e2dbd4SRam Kishore Vegesna 	if (buflen == 0) {
327*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "zero buffer length is invalid\n");
328*29e2dbd4SRam Kishore Vegesna 		return -1;
329*29e2dbd4SRam Kishore Vegesna 	}
330*29e2dbd4SRam Kishore Vegesna 
331*29e2dbd4SRam Kishore Vegesna 	num_buffers = ((buflen + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
332*29e2dbd4SRam Kishore Vegesna 
333*29e2dbd4SRam Kishore Vegesna 	dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers,
334*29e2dbd4SRam Kishore Vegesna 				  OCS_M_ZERO | OCS_M_NOWAIT);
335*29e2dbd4SRam Kishore Vegesna 	if (dump_buffers == NULL) {
336*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "Failed to allocate dump buffers\n");
337*29e2dbd4SRam Kishore Vegesna 		return -1;
338*29e2dbd4SRam Kishore Vegesna 	}
339*29e2dbd4SRam Kishore Vegesna 
340*29e2dbd4SRam Kishore Vegesna 	/* Allocate a DMA buffers to hold the dump */
341*29e2dbd4SRam Kishore Vegesna 	rem_bytes = buflen;
342*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
343*29e2dbd4SRam Kishore Vegesna 		uint32_t num_bytes = MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
344*29e2dbd4SRam Kishore Vegesna 		rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes,
345*29e2dbd4SRam Kishore Vegesna 				   OCS_MIN_DMA_ALIGNMENT);
346*29e2dbd4SRam Kishore Vegesna 		if (rc) {
347*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(ocs, "Failed to allocate dma buffer\n");
348*29e2dbd4SRam Kishore Vegesna 
349*29e2dbd4SRam Kishore Vegesna 			/* Free any previously allocated buffers */
350*29e2dbd4SRam Kishore Vegesna 			goto free_and_return;
351*29e2dbd4SRam Kishore Vegesna 		}
352*29e2dbd4SRam Kishore Vegesna 		rem_bytes -= num_bytes;
353*29e2dbd4SRam Kishore Vegesna 	}
354*29e2dbd4SRam Kishore Vegesna 
355*29e2dbd4SRam Kishore Vegesna 	/* register buffers for function spcific dump */
356*29e2dbd4SRam Kishore Vegesna 	rc = ocs_hw_set_dump_location(&ocs->hw, num_buffers, dump_buffers, 1);
357*29e2dbd4SRam Kishore Vegesna 	if (rc) {
358*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "ocs_hw_set_dump_location failed\n");
359*29e2dbd4SRam Kishore Vegesna 		goto free_and_return;
360*29e2dbd4SRam Kishore Vegesna 	}
361*29e2dbd4SRam Kishore Vegesna 
362*29e2dbd4SRam Kishore Vegesna 	/* Invoke dump by setting fdd=1 and ip=1 in sliport_control register */
363*29e2dbd4SRam Kishore Vegesna 	rc = ocs_fdb_dump(ocs);
364*29e2dbd4SRam Kishore Vegesna 	if (rc) {
365*29e2dbd4SRam Kishore Vegesna 		ocs_log_err(ocs, "ocs_gen_dump failed\n");
366*29e2dbd4SRam Kishore Vegesna 		goto free_and_return;
367*29e2dbd4SRam Kishore Vegesna 	}
368*29e2dbd4SRam Kishore Vegesna 
369*29e2dbd4SRam Kishore Vegesna 	/* Copy the dump from the DMA buffer into the user buffer */
370*29e2dbd4SRam Kishore Vegesna 	offset = 0;
371*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
372*29e2dbd4SRam Kishore Vegesna 		if (ocs_copy_to_user((uint8_t*)buf + offset,
373*29e2dbd4SRam Kishore Vegesna 		    dump_buffers[i].virt, dump_buffers[i].size)) {
374*29e2dbd4SRam Kishore Vegesna 			ocs_log_err(ocs, "ocs_copy_to_user failed\n");
375*29e2dbd4SRam Kishore Vegesna 			rc = -1;
376*29e2dbd4SRam Kishore Vegesna 		}
377*29e2dbd4SRam Kishore Vegesna 		offset += dump_buffers[i].size;
378*29e2dbd4SRam Kishore Vegesna 	}
379*29e2dbd4SRam Kishore Vegesna 
380*29e2dbd4SRam Kishore Vegesna free_and_return:
381*29e2dbd4SRam Kishore Vegesna 	/* Free the DMA buffer and return */
382*29e2dbd4SRam Kishore Vegesna 	for (i = 0; i < num_buffers; i++) {
383*29e2dbd4SRam Kishore Vegesna 		ocs_dma_free(ocs, &dump_buffers[i]);
384*29e2dbd4SRam Kishore Vegesna 	}
385*29e2dbd4SRam Kishore Vegesna 	ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
386*29e2dbd4SRam Kishore Vegesna 	return rc;
387*29e2dbd4SRam Kishore Vegesna 
388*29e2dbd4SRam Kishore Vegesna }
389