xref: /freebsd/sys/dev/ocs_fc/ocs_ddump.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1 /*-
2  * Copyright (c) 2017 Broadcom. All rights reserved.
3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /**
33  * @file
34  * generate FC ddump
35  *
36  */
37 
38 #include "ocs.h"
39 #include "ocs_ddump.h"
40 
41 #define DEFAULT_SAVED_DUMP_SIZE		(4*1024*1024)
42 
43 void hw_queue_ddump(ocs_textbuf_t *textbuf, ocs_hw_t *hw);
44 
45 /**
46  * @brief Generate sli4 queue ddump
47  *
48  * Generates sli4 queue ddump data
49  *
50  * @param textbuf pointer to text buffer
51  * @param name name of SLI4 queue
52  * @param hw pointer HW context
53  * @param q pointer to SLI4 queues array
54  * @param q_count count of SLI4 queues
55  * @param qentries number of SLI4 queue entries to dump
56  *
57  * @return none
58  */
59 
60 static void
61 ocs_ddump_sli4_queue(ocs_textbuf_t *textbuf, const char *name, ocs_hw_t *hw, sli4_queue_t *q, uint32_t q_count, uint32_t qentries)
62 {
63 	uint32_t i;
64 
65 	for (i = 0; i < q_count; i ++, q ++) {
66 		ocs_ddump_section(textbuf, name, i);
67 		ocs_ddump_value(textbuf, "index", "%d", q->index);
68 		ocs_ddump_value(textbuf, "size", "%d", q->size);
69 		ocs_ddump_value(textbuf, "length", "%d", q->length);
70 		ocs_ddump_value(textbuf, "n_posted", "%d", q->n_posted);
71 		ocs_ddump_value(textbuf, "id", "%d", q->id);
72 		ocs_ddump_value(textbuf, "type", "%d", q->type);
73 		ocs_ddump_value(textbuf, "proc_limit", "%d", q->proc_limit);
74 		ocs_ddump_value(textbuf, "posted_limit", "%d", q->posted_limit);
75 		ocs_ddump_value(textbuf, "max_num_processed", "%d", q->max_num_processed);
76 		ocs_ddump_value(textbuf, "max_process_time", "%ld", (unsigned long)q->max_process_time);
77 		ocs_ddump_value(textbuf, "virt_addr", "%p", q->dma.virt);
78 		ocs_ddump_value(textbuf, "phys_addr", "%lx", (unsigned long)q->dma.phys);
79 
80 		/* queue-specific information */
81 		switch (q->type) {
82 		case SLI_QTYPE_MQ:
83 			ocs_ddump_value(textbuf, "r_idx", "%d", q->u.r_idx);
84 			break;
85 		case SLI_QTYPE_CQ:
86 			ocs_ddump_value(textbuf, "is_mq", "%d", q->u.flag.is_mq);
87 			break;
88 		case SLI_QTYPE_WQ:
89 			break;
90 		case SLI_QTYPE_RQ: {
91 			uint32_t i;
92 			uint32_t j;
93 			uint32_t rqe_count = 0;
94 			hw_rq_t *rq;
95 
96 			ocs_ddump_value(textbuf, "is_hdr", "%d", q->u.flag.is_hdr);
97 			ocs_ddump_value(textbuf, "rq_batch", "%d", q->u.flag.rq_batch);
98 
99 			/* loop through RQ tracker to see how many RQEs were produced */
100 			for (i = 0; i < hw->hw_rq_count; i++) {
101 				rq = hw->hw_rq[i];
102 				for (j = 0; j < rq->entry_count; j++) {
103 					if (rq->rq_tracker[j] != NULL) {
104 						rqe_count++;
105 					}
106 				}
107 			}
108 			ocs_ddump_value(textbuf, "rqes_produced", "%d", rqe_count);
109 			break;
110 		}
111 		}
112 		ocs_ddump_queue_entries(textbuf, q->dma.virt, q->size, q->length,
113 					((q->type == SLI_QTYPE_MQ) ? q->u.r_idx : q->index),
114 					qentries);
115 		ocs_ddump_endsection(textbuf, name, i);
116 	}
117 }
118 
119 /**
120  * @brief Generate SLI4 ddump
121  *
122  * Generates sli4 ddump
123  *
124  * @param textbuf pointer to text buffer
125  * @param sli4 pointer SLI context
126  * @param qtype SLI4 queue type
127  *
128  * @return none
129  */
130 
131 static void
132 ocs_ddump_sli_q_fields(ocs_textbuf_t *textbuf, sli4_t *sli4, sli4_qtype_e qtype)
133 {
134 	char * q_desc;
135 
136 	switch(qtype) {
137 	case SLI_QTYPE_EQ: q_desc = "EQ"; break;
138 	case SLI_QTYPE_CQ: q_desc = "CQ"; break;
139 	case SLI_QTYPE_MQ: q_desc = "MQ"; break;
140 	case SLI_QTYPE_WQ: q_desc = "WQ"; break;
141 	case SLI_QTYPE_RQ: q_desc = "RQ"; break;
142 	default: q_desc = "unknown"; break;
143 	}
144 
145 	ocs_ddump_section(textbuf, q_desc, qtype);
146 
147 	ocs_ddump_value(textbuf, "max_qcount", "%d", sli4->config.max_qcount[qtype]);
148 	ocs_ddump_value(textbuf, "max_qentries", "%d", sli4->config.max_qentries[qtype]);
149 	ocs_ddump_value(textbuf, "qpage_count", "%d", sli4->config.qpage_count[qtype]);
150 	ocs_ddump_endsection(textbuf, q_desc, qtype);
151 }
152 
153 /**
154  * @brief Generate SLI4 ddump
155  *
156  * Generates sli4 ddump
157  *
158  * @param textbuf pointer to text buffer
159  * @param sli4 pointer SLI context
160  *
161  * @return none
162  */
163 
164 static void
165 ocs_ddump_sli(ocs_textbuf_t *textbuf, sli4_t *sli4)
166 {
167 	sli4_sgl_chaining_params_t *cparams = &sli4->config.sgl_chaining_params;
168 	const char *p;
169 
170 	ocs_ddump_section(textbuf, "sli4", 0);
171 
172 	ocs_ddump_value(textbuf, "sli_rev", "%d", sli4->sli_rev);
173 	ocs_ddump_value(textbuf, "sli_family", "%d", sli4->sli_family);
174 	ocs_ddump_value(textbuf, "if_type", "%d", sli4->if_type);
175 
176 	switch(sli4->asic_type) {
177 	case SLI4_ASIC_TYPE_BE3:	p = "BE3"; break;
178 	case SLI4_ASIC_TYPE_SKYHAWK:	p = "Skyhawk"; break;
179 	case SLI4_ASIC_TYPE_LANCER:	p = "Lancer"; break;
180 	case SLI4_ASIC_TYPE_LANCERG6:	p = "LancerG6"; break;
181 	default:			p = "unknown"; break;
182 	}
183 	ocs_ddump_value(textbuf, "asic_type", "%s", p);
184 
185 	switch(sli4->asic_rev) {
186 	case SLI4_ASIC_REV_FPGA:	p = "fpga"; break;
187 	case SLI4_ASIC_REV_A0:		p = "A0"; break;
188 	case SLI4_ASIC_REV_A1:		p = "A1"; break;
189 	case SLI4_ASIC_REV_A2:		p = "A2"; break;
190 	case SLI4_ASIC_REV_A3:		p = "A3"; break;
191 	case SLI4_ASIC_REV_B0:		p = "B0"; break;
192 	case SLI4_ASIC_REV_C0:		p = "C0"; break;
193 	case SLI4_ASIC_REV_D0:		p = "D0"; break;
194 	default:			p = "unknown"; break;
195 	}
196 	ocs_ddump_value(textbuf, "asic_rev", "%s", p);
197 
198 	ocs_ddump_value(textbuf, "e_d_tov", "%d", sli4->config.e_d_tov);
199 	ocs_ddump_value(textbuf, "r_a_tov", "%d", sli4->config.r_a_tov);
200 	ocs_ddump_value(textbuf, "link_module_type", "%d", sli4->config.link_module_type);
201 	ocs_ddump_value(textbuf, "rq_batch", "%d", sli4->config.rq_batch);
202 	ocs_ddump_value(textbuf, "topology", "%d", sli4->config.topology);
203 	ocs_ddump_value(textbuf, "wwpn", "%02x%02x%02x%02x%02x%02x%02x%02x",
204 			 sli4->config.wwpn[0],
205 			 sli4->config.wwpn[1],
206 			 sli4->config.wwpn[2],
207 			 sli4->config.wwpn[3],
208 			 sli4->config.wwpn[4],
209 			 sli4->config.wwpn[5],
210 			 sli4->config.wwpn[6],
211 			 sli4->config.wwpn[7]);
212 	ocs_ddump_value(textbuf, "wwnn", "%02x%02x%02x%02x%02x%02x%02x%02x",
213 			 sli4->config.wwnn[0],
214 			 sli4->config.wwnn[1],
215 			 sli4->config.wwnn[2],
216 			 sli4->config.wwnn[3],
217 			 sli4->config.wwnn[4],
218 			 sli4->config.wwnn[5],
219 			 sli4->config.wwnn[6],
220 			 sli4->config.wwnn[7]);
221 	ocs_ddump_value(textbuf, "fw_rev0", "%d", sli4->config.fw_rev[0]);
222 	ocs_ddump_value(textbuf, "fw_rev1", "%d", sli4->config.fw_rev[1]);
223 	ocs_ddump_value(textbuf, "fw_name0", "%s", (char*)sli4->config.fw_name[0]);
224 	ocs_ddump_value(textbuf, "fw_name1", "%s", (char*)sli4->config.fw_name[1]);
225 	ocs_ddump_value(textbuf, "hw_rev0", "%x", sli4->config.hw_rev[0]);
226 	ocs_ddump_value(textbuf, "hw_rev1", "%x", sli4->config.hw_rev[1]);
227 	ocs_ddump_value(textbuf, "hw_rev2", "%x", sli4->config.hw_rev[2]);
228 	ocs_ddump_value(textbuf, "sge_supported_length", "%x", sli4->config.sge_supported_length);
229 	ocs_ddump_value(textbuf, "sgl_page_sizes", "%x", sli4->config.sgl_page_sizes);
230 	ocs_ddump_value(textbuf, "max_sgl_pages", "%x", sli4->config.max_sgl_pages);
231 	ocs_ddump_value(textbuf, "high_login_mode", "%x", sli4->config.high_login_mode);
232 	ocs_ddump_value(textbuf, "sgl_pre_registered", "%x", sli4->config.sgl_pre_registered);
233 	ocs_ddump_value(textbuf, "sgl_pre_registration_required", "%x", sli4->config.sgl_pre_registration_required);
234 
235 	ocs_ddump_value(textbuf, "sgl_chaining_capable", "%x", cparams->chaining_capable);
236 	ocs_ddump_value(textbuf, "frag_num_field_offset", "%x", cparams->frag_num_field_offset);
237 	ocs_ddump_value(textbuf, "frag_num_field_mask", "%016llx", (unsigned long long)cparams->frag_num_field_mask);
238 	ocs_ddump_value(textbuf, "sgl_index_field_offset", "%x", cparams->sgl_index_field_offset);
239 	ocs_ddump_value(textbuf, "sgl_index_field_mask", "%016llx", (unsigned long long)cparams->sgl_index_field_mask);
240 	ocs_ddump_value(textbuf, "chain_sge_initial_value_lo", "%x", cparams->chain_sge_initial_value_lo);
241 	ocs_ddump_value(textbuf, "chain_sge_initial_value_hi", "%x", cparams->chain_sge_initial_value_hi);
242 
243 	ocs_ddump_value(textbuf, "max_vfi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_VFI));
244 	ocs_ddump_value(textbuf, "max_vpi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_VPI));
245 	ocs_ddump_value(textbuf, "max_rpi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_RPI));
246 	ocs_ddump_value(textbuf, "max_xri", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_XRI));
247 	ocs_ddump_value(textbuf, "max_fcfi", "%d", sli_get_max_rsrc(sli4, SLI_RSRC_FCOE_FCFI));
248 
249 	ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_EQ);
250 	ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_CQ);
251 	ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_MQ);
252 	ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_WQ);
253 	ocs_ddump_sli_q_fields(textbuf, sli4, SLI_QTYPE_RQ);
254 
255 	ocs_ddump_endsection(textbuf, "sli4", 0);
256 }
257 
258 /**
259  * @brief Dump HW IO
260  *
261  * Dump HW IO
262  *
263  * @param textbuf pointer to text buffer
264  * @param io pointer to HW IO object
265  *
266  * @return none
267  */
268 
269 static void
270 ocs_ddump_hw_io(ocs_textbuf_t *textbuf, ocs_hw_io_t *io)
271 {
272 	ocs_assert(io);
273 
274 	ocs_ddump_section(textbuf, "hw_io", io->indicator);
275 
276 	ocs_ddump_value(textbuf, "state", "%d", io->state);
277 	ocs_ddump_value(textbuf, "xri", "0x%x", io->indicator);
278 	ocs_ddump_value(textbuf, "tag", "0x%x", io->reqtag);
279 	ocs_ddump_value(textbuf, "abort_reqtag", "0x%x", io->abort_reqtag);
280 	ocs_ddump_value(textbuf, "ref_count", "%d", ocs_ref_read_count(&io->ref));
281 
282 	/* just to make it obvious, display abort bit from tag */
283 	ocs_ddump_value(textbuf, "abort", "0x%x", io->abort_in_progress);
284 	ocs_ddump_value(textbuf, "wq_index", "%d", (io->wq == NULL ? 0xffff : io->wq->instance));
285 	ocs_ddump_value(textbuf, "type", "%d", io->type);
286 	ocs_ddump_value(textbuf, "xbusy", "%d", io->xbusy);
287 	ocs_ddump_value(textbuf, "active_wqe_link", "%d", ocs_list_on_list(&io->wqe_link));
288 	ocs_ddump_value(textbuf, "def_sgl_count", "%d", io->def_sgl_count);
289 	ocs_ddump_value(textbuf, "n_sge", "%d", io->n_sge);
290 	ocs_ddump_value(textbuf, "has_ovfl_sgl", "%s", (io->ovfl_sgl != NULL ? "TRUE" : "FALSE"));
291 	ocs_ddump_value(textbuf, "has_ovfl_io", "%s", (io->ovfl_io != NULL ? "TRUE" : "FALSE"));
292 
293 	ocs_ddump_endsection(textbuf, "hw_io", io->indicator);
294 }
295 
296 #if defined(OCS_DEBUG_QUEUE_HISTORY)
297 
298 /**
299  * @brief Generate queue history ddump
300  *
301  * @param textbuf pointer to text buffer
302  * @param q_hist Pointer to queue history object.
303  */
304 static void
305 ocs_ddump_queue_history(ocs_textbuf_t *textbuf, ocs_hw_q_hist_t *q_hist)
306 {
307 	uint32_t x;
308 
309 	ocs_ddump_section(textbuf, "q_hist", 0);
310 	ocs_ddump_value(textbuf, "count", "%ld", OCS_Q_HIST_SIZE);
311 	ocs_ddump_value(textbuf, "index", "%d", q_hist->q_hist_index);
312 
313 	if (q_hist->q_hist == NULL) {
314 		ocs_ddump_section(textbuf, "history", 0);
315 		ocs_textbuf_printf(textbuf, "No history available\n");
316 		ocs_ddump_endsection(textbuf, "history", 0);
317 		ocs_ddump_endsection(textbuf, "q_hist", 0);
318 		return;
319 	}
320 
321 	/* start from last entry and go backwards */
322 	ocs_textbuf_printf(textbuf, "<history>\n");
323 	ocs_textbuf_printf(textbuf, "(newest first):\n");
324 
325 	ocs_lock(&q_hist->q_hist_lock);
326 	x = ocs_queue_history_prev_index(q_hist->q_hist_index);
327 	do {
328 		int i;
329 		ocs_q_hist_ftr_t ftr;
330 		uint32_t mask;
331 
332 		/* footer's mask indicates what words were captured */
333 		ftr.word = q_hist->q_hist[x];
334 		mask = ftr.s.mask;
335 		i = 0;
336 
337 		/* if we've encountered a mask of 0, must be done */
338 		if (mask == 0) {
339 			break;
340 		}
341 
342 		/* display entry type */
343 		ocs_textbuf_printf(textbuf, "%s:\n",
344 				   ocs_queue_history_type_name(ftr.s.type));
345 
346 		if (ocs_queue_history_timestamp_enabled()) {
347 			uint64_t tsc_value;
348 			x = ocs_queue_history_prev_index(x);
349 			tsc_value = ((q_hist->q_hist[x]) & 0x00000000FFFFFFFFull);
350 			x = ocs_queue_history_prev_index(x);
351 			tsc_value |= (((uint64_t)q_hist->q_hist[x] << 32) & 0xFFFFFFFF00000000ull);
352 			ocs_textbuf_printf(textbuf, " t: %" PRIu64 "\n", tsc_value);
353 		}
354 
355 		if (ocs_queue_history_q_info_enabled()) {
356 			if (ftr.s.type == OCS_Q_HIST_TYPE_CWQE ||
357 			    ftr.s.type == OCS_Q_HIST_TYPE_CXABT ||
358 			    ftr.s.type == OCS_Q_HIST_TYPE_WQE) {
359 				x = ocs_queue_history_prev_index(x);
360 				ocs_textbuf_printf(textbuf, " qid=0x%x idx=0x%x\n",
361 						   ((q_hist->q_hist[x] >> 16) & 0xFFFF),
362 						   ((q_hist->q_hist[x] >> 0) & 0xFFFF));
363 			}
364 		}
365 
366 		while (mask) {
367 			if ((mask & 1) && (x != q_hist->q_hist_index)){
368 				/* get next word */
369 				x = ocs_queue_history_prev_index(x);
370 				ocs_textbuf_printf(textbuf, " [%d]=%x\n",
371 						   i, q_hist->q_hist[x]);
372 			}
373 			mask = (mask >> 1UL);
374 			i++;
375 		}
376 
377 		/* go backwards to next element */
378 		x = ocs_queue_history_prev_index(x);
379 	} while (x != ocs_queue_history_prev_index(q_hist->q_hist_index));
380 	ocs_unlock(&q_hist->q_hist_lock);
381 
382 	ocs_textbuf_printf(textbuf, "</history>\n");
383 	ocs_ddump_endsection(textbuf, "q_hist", 0);
384 }
385 #endif
386 
387 /**
388  * @brief Generate hw ddump
389  *
390  * Generates hw ddump
391  *
392  * @param textbuf pointer to text buffer
393  * @param hw pointer HW context
394  * @param flags ddump flags
395  * @param qentries number of qentries to dump
396  *
397  * @return none
398  */
399 
400 static void
401 ocs_ddump_hw(ocs_textbuf_t *textbuf, ocs_hw_t *hw, uint32_t flags, uint32_t qentries)
402 {
403 	ocs_t *ocs = hw->os;
404 	uint32_t cnt = 0;
405 	ocs_hw_io_t *io = NULL;
406 	uint32_t i;
407 	uint32_t j;
408 	uint32_t max_rpi = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI);
409 
410 	ocs_assert(ocs);
411 
412 	ocs_ddump_section(textbuf, "hw", ocs->instance_index);
413 
414 	/* device specific information */
415 	switch(hw->sli.if_type) {
416 	case 0:
417 		ocs_ddump_value(textbuf, "uerr_mask_hi", "%08x",
418 				 sli_reg_read(&hw->sli, SLI4_REG_UERR_MASK_HI));
419 		ocs_ddump_value(textbuf, "uerr_mask_lo", "%08x",
420 				 sli_reg_read(&hw->sli, SLI4_REG_UERR_MASK_LO));
421 		ocs_ddump_value(textbuf, "uerr_status_hi", "%08x",
422 				 sli_reg_read(&hw->sli, SLI4_REG_UERR_STATUS_HI));
423 		ocs_ddump_value(textbuf, "uerr_status_lo", "%08x",
424 				 sli_reg_read(&hw->sli, SLI4_REG_UERR_STATUS_LO));
425 		break;
426 	case 2:
427 		ocs_ddump_value(textbuf, "sliport_status", "%08x",
428 				 sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_STATUS));
429 		ocs_ddump_value(textbuf, "sliport_error1", "%08x",
430 				 sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR1));
431 		ocs_ddump_value(textbuf, "sliport_error2", "%08x",
432 				 sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR2));
433 		break;
434 	}
435 
436 	ocs_ddump_value(textbuf, "link_status", "%d", hw->link.status);
437 	ocs_ddump_value(textbuf, "link_speed", "%d", hw->link.speed);
438 	ocs_ddump_value(textbuf, "link_topology", "%d", hw->link.topology);
439 	ocs_ddump_value(textbuf, "state", "%d", hw->state);
440 	ocs_ddump_value(textbuf, "io_alloc_failed_count", "%d", ocs_atomic_read(&hw->io_alloc_failed_count));
441 	ocs_ddump_value(textbuf, "n_io", "%d", hw->config.n_io);
442 
443 	ocs_ddump_value(textbuf, "queue_topology", "%s", hw->config.queue_topology);
444 	ocs_ddump_value(textbuf, "rq_selection_policy", "%d", hw->config.rq_selection_policy);
445 	ocs_ddump_value(textbuf, "rr_quanta", "%d", hw->config.rr_quanta);
446 	for (i = 0; i < ARRAY_SIZE(hw->config.filter_def); i++) {
447 		ocs_ddump_value(textbuf, "filter_def", "%08X", hw->config.filter_def[i]);
448 	}
449 	ocs_ddump_value(textbuf, "n_eq", "%d", hw->eq_count);
450 	ocs_ddump_value(textbuf, "n_cq", "%d", hw->cq_count);
451 	ocs_ddump_value(textbuf, "n_mq", "%d", hw->mq_count);
452 	ocs_ddump_value(textbuf, "n_rq", "%d", hw->rq_count);
453 	ocs_ddump_value(textbuf, "n_wq", "%d", hw->wq_count);
454 	ocs_ddump_value(textbuf, "n_sgl", "%d", hw->config.n_sgl);
455 
456 	ocs_ddump_sli(textbuf, &hw->sli);
457 
458 	ocs_ddump_sli4_queue(textbuf, "wq", hw, hw->wq, hw->wq_count,
459 			((flags & OCS_DDUMP_FLAGS_WQES) ? qentries : 0));
460 	ocs_ddump_sli4_queue(textbuf, "rq", hw, hw->rq, hw->rq_count,
461 			((flags & OCS_DDUMP_FLAGS_RQES) ? qentries : 0));
462 	ocs_ddump_sli4_queue(textbuf, "mq", hw, hw->mq, hw->mq_count,
463 			((flags & OCS_DDUMP_FLAGS_MQES) ? qentries : 0));
464 	ocs_ddump_sli4_queue(textbuf, "cq", hw, hw->cq, hw->cq_count,
465 			((flags & OCS_DDUMP_FLAGS_CQES) ? qentries : 0));
466 	ocs_ddump_sli4_queue(textbuf, "eq", hw, hw->eq, hw->eq_count,
467 			((flags & OCS_DDUMP_FLAGS_EQES) ? qentries : 0));
468 
469 	/* dump the IO quarantine list */
470 	for (i = 0; i < hw->wq_count; i++) {
471 		ocs_ddump_section(textbuf, "io_quarantine", i);
472 		ocs_ddump_value(textbuf, "quarantine_index", "%d", hw->hw_wq[i]->quarantine_info.quarantine_index);
473 		for (j = 0; j < OCS_HW_QUARANTINE_QUEUE_DEPTH; j++) {
474 			if (hw->hw_wq[i]->quarantine_info.quarantine_ios[j] != NULL) {
475 				ocs_ddump_hw_io(textbuf, hw->hw_wq[i]->quarantine_info.quarantine_ios[j]);
476 			}
477 		}
478 		ocs_ddump_endsection(textbuf, "io_quarantine", i);
479 	}
480 
481 	ocs_ddump_section(textbuf, "workaround", ocs->instance_index);
482 	ocs_ddump_value(textbuf, "fwrev", "%08llx", (unsigned long long)hw->workaround.fwrev);
483 	ocs_ddump_endsection(textbuf, "workaround", ocs->instance_index);
484 
485 	ocs_lock(&hw->io_lock);
486 		ocs_ddump_section(textbuf, "io_inuse", ocs->instance_index);
487 		ocs_list_foreach(&hw->io_inuse, io) {
488 			ocs_ddump_hw_io(textbuf, io);
489 		}
490 		ocs_ddump_endsection(textbuf, "io_inuse", ocs->instance_index);
491 
492 		ocs_ddump_section(textbuf, "io_wait_free", ocs->instance_index);
493 		ocs_list_foreach(&hw->io_wait_free, io) {
494 			ocs_ddump_hw_io(textbuf, io);
495 		}
496 		ocs_ddump_endsection(textbuf, "io_wait_free", ocs->instance_index);
497 		ocs_ddump_section(textbuf, "io_free", ocs->instance_index);
498 		ocs_list_foreach(&hw->io_free, io) {
499 			if (io->xbusy) {
500 				/* only display free ios if they're active */
501 				ocs_ddump_hw_io(textbuf, io);
502 			}
503 			cnt++;
504 		}
505 		ocs_ddump_endsection(textbuf, "io_free", ocs->instance_index);
506 		ocs_ddump_value(textbuf, "ios_free", "%d", cnt);
507 
508 	ocs_ddump_value(textbuf, "sec_hio_wait_count", "%d", hw->sec_hio_wait_count);
509 	ocs_unlock(&hw->io_lock);
510 
511 	/* now check the IOs not in a list; i.e. sequence coalescing xris */
512 	ocs_ddump_section(textbuf, "port_owned_ios", ocs->instance_index);
513 	for (i = 0; i < hw->config.n_io; i++) {
514 		io = hw->io[i];
515 		if (!io)
516 			continue;
517 
518 		if (ocs_hw_is_xri_port_owned(hw, io->indicator)) {
519 			if (ocs_ref_read_count(&io->ref)) {
520 				/* only display free ios if they're active */
521 				ocs_ddump_hw_io(textbuf, io);
522 			}
523 		}
524 	}
525 	ocs_ddump_endsection(textbuf, "port_owned_ios", ocs->instance_index);
526 
527 	ocs_textbuf_printf(textbuf, "<rpi_ref>");
528 	for (i = 0; i < max_rpi; i++) {
529 		if (ocs_atomic_read(&hw->rpi_ref[i].rpi_attached) ||
530 			ocs_atomic_read(&hw->rpi_ref[i].rpi_count) ) {
531 			ocs_textbuf_printf(textbuf, "[%d] att=%d cnt=%d\n", i,
532 				ocs_atomic_read(&hw->rpi_ref[i].rpi_attached),
533 				ocs_atomic_read(&hw->rpi_ref[i].rpi_count));
534 		}
535 	}
536 	ocs_textbuf_printf(textbuf, "</rpi_ref>");
537 
538 	for (i = 0; i < hw->wq_count; i++) {
539 		ocs_ddump_value(textbuf, "wq_submit", "%d", hw->tcmd_wq_submit[i]);
540 	}
541 	for (i = 0; i < hw->wq_count; i++) {
542 		ocs_ddump_value(textbuf, "wq_complete", "%d", hw->tcmd_wq_complete[i]);
543 	}
544 
545 	hw_queue_ddump(textbuf, hw);
546 
547 	ocs_ddump_endsection(textbuf, "hw", ocs->instance_index);
548 
549 }
550 
551 void
552 hw_queue_ddump(ocs_textbuf_t *textbuf, ocs_hw_t *hw)
553 {
554 	hw_eq_t *eq;
555 	hw_cq_t *cq;
556 	hw_q_t *q;
557 	hw_mq_t *mq;
558 	hw_wq_t *wq;
559 	hw_rq_t *rq;
560 
561 	ocs_ddump_section(textbuf, "hw_queue", 0);
562 	ocs_list_foreach(&hw->eq_list, eq) {
563 		ocs_ddump_section(textbuf, "eq", eq->instance);
564 		ocs_ddump_value(textbuf, "queue-id", "%d", eq->queue->id);
565 		OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", eq->use_count));
566 		ocs_list_foreach(&eq->cq_list, cq) {
567 			ocs_ddump_section(textbuf, "cq", cq->instance);
568 			ocs_ddump_value(textbuf, "queue-id", "%d", cq->queue->id);
569 			OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", cq->use_count));
570 			ocs_list_foreach(&cq->q_list, q) {
571 				switch(q->type) {
572 				case SLI_QTYPE_MQ:
573 					mq = (hw_mq_t *) q;
574 					ocs_ddump_section(textbuf, "mq", mq->instance);
575 					ocs_ddump_value(textbuf, "queue-id", "%d", mq->queue->id);
576 					OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", mq->use_count));
577 					ocs_ddump_endsection(textbuf, "mq", mq->instance);
578 					break;
579 				case SLI_QTYPE_WQ:
580 					wq = (hw_wq_t *) q;
581 					ocs_ddump_section(textbuf, "wq", wq->instance);
582 					ocs_ddump_value(textbuf, "queue-id", "%d", wq->queue->id);
583 					OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", wq->use_count));
584 					ocs_ddump_value(textbuf, "wqec_count", "%d", wq->wqec_count);
585 					ocs_ddump_value(textbuf, "free_count", "%d", wq->free_count);
586 					OCS_STAT(ocs_ddump_value(textbuf, "wq_pending_count", "%d",
587 								 wq->wq_pending_count));
588 					ocs_ddump_endsection(textbuf, "wq", wq->instance);
589 					break;
590 				case SLI_QTYPE_RQ:
591 					rq = (hw_rq_t *) q;
592 					ocs_ddump_section(textbuf, "rq", rq->instance);
593 					OCS_STAT(ocs_ddump_value(textbuf, "use_count", "%d", rq->use_count));
594 					ocs_ddump_value(textbuf, "filter_mask", "%d", rq->filter_mask);
595 					if (rq->hdr != NULL) {
596 						ocs_ddump_value(textbuf, "hdr-id", "%d", rq->hdr->id);
597 						OCS_STAT(ocs_ddump_value(textbuf, "hdr_use_count", "%d", rq->hdr_use_count));
598 					}
599 					if (rq->first_burst != NULL) {
600 						OCS_STAT(ocs_ddump_value(textbuf, "fb-id", "%d", rq->first_burst->id));
601 						OCS_STAT(ocs_ddump_value(textbuf, "fb_use_count", "%d", rq->fb_use_count));
602 					}
603 					if (rq->data != NULL) {
604 						OCS_STAT(ocs_ddump_value(textbuf, "payload-id", "%d", rq->data->id));
605 						OCS_STAT(ocs_ddump_value(textbuf, "payload_use_count", "%d", rq->payload_use_count));
606 					}
607 					ocs_ddump_endsection(textbuf, "rq", rq->instance);
608 					break;
609 				default:
610 					break;
611 				}
612 			}
613 			ocs_ddump_endsection(textbuf, "cq", cq->instance);
614 		}
615 		ocs_ddump_endsection(textbuf, "eq", eq->instance);
616 	}
617 	ocs_ddump_endsection(textbuf, "hw_queue", 0);
618 }
619 
620 /**
621  * @brief Initiate ddump
622  *
623  * Traverses the ocs/domain/port/node/io data structures to generate a driver
624  * dump.
625  *
626  * @param ocs pointer to device context
627  * @param textbuf pointer to text buffer
628  * @param flags ddump flags
629  * @param qentries number of queue entries to dump
630  *
631  * @return Returns 0 on success, or a negative value on failure.
632  */
633 
634 int
635 ocs_ddump(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t flags, uint32_t qentries)
636 {
637 	ocs_xport_t *xport = ocs->xport;
638 	ocs_domain_t *domain;
639 	uint32_t instance;
640 	ocs_vport_spec_t *vport;
641 	ocs_io_t *io;
642 	int retval = 0;
643 	uint32_t i;
644 
645 	ocs_ddump_startfile(textbuf);
646 
647 	ocs_ddump_section(textbuf, "ocs", ocs->instance_index);
648 
649 	ocs_ddump_section(textbuf, "ocs_os", ocs->instance_index);
650 #ifdef OCS_ENABLE_NUMA_SUPPORT
651 	ocs_ddump_value(textbuf, "numa_node", "%d", ocs->ocs_os.numa_node);
652 #endif
653 	ocs_ddump_endsection(textbuf, "ocs_os", ocs->instance_index);
654 
655 	ocs_ddump_value(textbuf, "drv_name", "%s", DRV_NAME);
656 	ocs_ddump_value(textbuf, "drv_version", "%s", DRV_VERSION);
657 	ocs_ddump_value(textbuf, "display_name", "%s", ocs->display_name);
658 	ocs_ddump_value(textbuf, "enable_ini", "%d", ocs->enable_ini);
659 	ocs_ddump_value(textbuf, "enable_tgt", "%d", ocs->enable_tgt);
660 	ocs_ddump_value(textbuf, "nodes_count", "%d", xport->nodes_count);
661 	ocs_ddump_value(textbuf, "enable_hlm", "%d", ocs->enable_hlm);
662 	ocs_ddump_value(textbuf, "hlm_group_size", "%d", ocs->hlm_group_size);
663 	ocs_ddump_value(textbuf, "auto_xfer_rdy_size", "%d", ocs->auto_xfer_rdy_size);
664 	ocs_ddump_value(textbuf, "io_alloc_failed_count", "%d", ocs_atomic_read(&xport->io_alloc_failed_count));
665 	ocs_ddump_value(textbuf, "io_active_count", "%d", ocs_atomic_read(&xport->io_active_count));
666 	ocs_ddump_value(textbuf, "io_pending_count", "%d", ocs_atomic_read(&xport->io_pending_count));
667 	ocs_ddump_value(textbuf, "io_total_alloc", "%d", ocs_atomic_read(&xport->io_total_alloc));
668 	ocs_ddump_value(textbuf, "io_total_free", "%d", ocs_atomic_read(&xport->io_total_free));
669 	ocs_ddump_value(textbuf, "io_total_pending", "%d", ocs_atomic_read(&xport->io_total_pending));
670 	ocs_ddump_value(textbuf, "io_pending_recursing", "%d", ocs_atomic_read(&xport->io_pending_recursing));
671 	ocs_ddump_value(textbuf, "max_isr_time_msec", "%d", ocs->max_isr_time_msec);
672 	for (i = 0; i < SLI4_MAX_FCFI; i++) {
673 		ocs_lock(&xport->fcfi[i].pend_frames_lock);
674 		if (!ocs_list_empty(&xport->fcfi[i].pend_frames)) {
675 			ocs_hw_sequence_t *frame;
676 			ocs_ddump_section(textbuf, "pending_frames", i);
677 			ocs_ddump_value(textbuf, "hold_frames", "%d", xport->fcfi[i].hold_frames);
678 			ocs_list_foreach(&xport->fcfi[i].pend_frames, frame) {
679 				fc_header_t *hdr;
680 				char buf[128];
681 
682 				hdr = frame->header->dma.virt;
683 				ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu",
684 				 hdr->r_ctl, ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
685 				 frame->payload->dma.len);
686 				ocs_ddump_value(textbuf, "frame", "%s", buf);
687 			}
688 			ocs_ddump_endsection(textbuf, "pending_frames", i);
689 		}
690 		ocs_unlock(&xport->fcfi[i].pend_frames_lock);
691 	}
692 
693 	ocs_lock(&xport->io_pending_lock);
694 		ocs_ddump_section(textbuf, "io_pending_list", ocs->instance_index);
695 		ocs_list_foreach(&xport->io_pending_list, io) {
696 			ocs_ddump_io(textbuf, io);
697 		}
698 		ocs_ddump_endsection(textbuf, "io_pending_list", ocs->instance_index);
699 	ocs_unlock(&xport->io_pending_lock);
700 
701 #if defined(ENABLE_LOCK_DEBUG)
702 	/* Dump the lock list */
703 	ocs_ddump_section(textbuf, "locks", 0);
704 	ocs_lock(&ocs->ocs_os.locklist_lock); {
705 		ocs_lock_t *l;
706 		uint32_t idx = 0;
707 		ocs_list_foreach(&ocs->ocs_os.locklist, l) {
708 			ocs_ddump_section(textbuf, "lock", idx);
709 			ocs_ddump_value(textbuf, "name", "%s", l->name);
710 			ocs_ddump_value(textbuf, "inuse", "%d", l->inuse);
711 			ocs_ddump_value(textbuf, "caller", "%p", l->caller[0]);
712 			ocs_ddump_value(textbuf, "pid", "%08x", l->pid.l);
713 			ocs_ddump_endsection(textbuf, "lock", idx);
714 			idx++;
715 		}
716 	} ocs_unlock(&ocs->ocs_os.locklist_lock);
717 	ocs_ddump_endsection(textbuf, "locks", 0);
718 #endif
719 
720 	/* Dump any pending vports */
721 	if (ocs_device_lock_try(ocs) != TRUE) {
722 		/* Didn't get the lock */
723 		return -1;
724 	}
725 		instance = 0;
726 		ocs_list_foreach(&xport->vport_list, vport) {
727 			ocs_ddump_section(textbuf, "vport_spec", instance);
728 			ocs_ddump_value(textbuf, "domain_instance", "%d", vport->domain_instance);
729 			ocs_ddump_value(textbuf, "wwnn", "%llx", (unsigned long long)vport->wwnn);
730 			ocs_ddump_value(textbuf, "wwpn", "%llx", (unsigned long long)vport->wwpn);
731 			ocs_ddump_value(textbuf, "fc_id", "0x%x", vport->fc_id);
732 			ocs_ddump_value(textbuf, "enable_tgt", "%d", vport->enable_tgt);
733 			ocs_ddump_value(textbuf, "enable_ini", "%d" PRIx64, vport->enable_ini);
734 			ocs_ddump_endsection(textbuf, "vport_spec", instance ++);
735 		}
736 	ocs_device_unlock(ocs);
737 
738 	/* Dump target and initiator private data */
739 	ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_DEVICE, ocs);
740 	ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_DEVICE, ocs);
741 
742 	ocs_ddump_hw(textbuf, &ocs->hw, flags, qentries);
743 
744 	if (ocs_device_lock_try(ocs) != TRUE) {
745 		/* Didn't get the lock */
746 		return -1;
747 	}
748 		/* Here the device lock is held */
749 		ocs_list_foreach(&ocs->domain_list, domain) {
750 			retval = ocs_ddump_domain(textbuf, domain);
751 			if (retval != 0) {
752 				break;
753 			}
754 		}
755 
756 		/* Dump ramlog */
757 		ocs_ddump_ramlog(textbuf, ocs->ramlog);
758 	ocs_device_unlock(ocs);
759 
760 #if !defined(OCS_DEBUG_QUEUE_HISTORY)
761 	ocs_ddump_section(textbuf, "q_hist", ocs->instance_index);
762 	ocs_textbuf_printf(textbuf, "<history>\n");
763 	ocs_textbuf_printf(textbuf, "No history available\n");
764 	ocs_textbuf_printf(textbuf, "</history>\n");
765 	ocs_ddump_endsection(textbuf, "q_hist", ocs->instance_index);
766 #else
767 	ocs_ddump_queue_history(textbuf, &ocs->hw.q_hist);
768 #endif
769 
770 #if defined(OCS_DEBUG_MEMORY)
771 	ocs_memory_allocated_ddump(textbuf);
772 #endif
773 
774 	ocs_ddump_endsection(textbuf, "ocs", ocs->instance_index);
775 
776 	ocs_ddump_endfile(textbuf);
777 
778 	return retval;
779 }
780 
781 /**
782  * @brief Capture and save ddump
783  *
784  * Captures and saves a ddump to the ocs_t structure to save the
785  * current state. The goal of this function is to save a ddump
786  * as soon as an issue is encountered. The saved ddump will be
787  * kept until the user reads it.
788  *
789  * @param ocs pointer to device context
790  * @param flags ddump flags
791  * @param qentries number of queue entries to dump
792  *
793  * @return 0 if ddump was saved; > 0 of one already exists; < 0
794  * error
795  */
796 
797 int32_t
798 ocs_save_ddump(ocs_t *ocs, uint32_t flags, uint32_t qentries)
799 {
800 	if (ocs_textbuf_get_written(&ocs->ddump_saved) > 0) {
801 		ocs_log_debug(ocs, "Saved ddump already exists\n");
802 		return 1;
803 	}
804 
805 	if (!ocs_textbuf_initialized(&ocs->ddump_saved)) {
806 		ocs_log_err(ocs, "Saved ddump not allocated\n");
807 		return -1;
808 	}
809 
810 	ocs_log_debug(ocs, "Saving ddump\n");
811 	ocs_ddump(ocs, &ocs->ddump_saved, flags, qentries);
812 	ocs_log_debug(ocs, "Saved ddump: %d bytes written\n", ocs_textbuf_get_written(&ocs->ddump_saved));
813 	return 0;
814 }
815 
816 /**
817  * @brief Capture and save ddump for all OCS instances
818  *
819  * Calls ocs_save_ddump() for each OCS instance.
820  *
821  * @param flags ddump flags
822  * @param qentries number of queue entries to dump
823  * @param alloc_flag allocate dump buffer if not already allocated
824  *
825  * @return 0 if ddump was saved; > 0 of one already exists; < 0
826  * error
827  */
828 
829 int32_t
830 ocs_save_ddump_all(uint32_t flags, uint32_t qentries, uint32_t alloc_flag)
831 {
832 	ocs_t *ocs;
833 	uint32_t i;
834 	int32_t rc = 0;
835 
836 	for (i = 0; (ocs = ocs_get_instance(i)) != NULL; i++) {
837 		if (alloc_flag && (!ocs_textbuf_initialized(&ocs->ddump_saved))) {
838 			rc = ocs_textbuf_alloc(ocs, &ocs->ddump_saved, DEFAULT_SAVED_DUMP_SIZE);
839 			if (rc) {
840 				break;
841 			}
842 		}
843 
844 		rc = ocs_save_ddump(ocs, flags, qentries);
845 		if (rc < 0) {
846 			break;
847 		}
848 	}
849 	return rc;
850 }
851 
852 /**
853  * @brief Clear saved ddump
854  *
855  * Clears saved ddump to make room for next one.
856  *
857  * @param ocs pointer to device context
858  *
859  * @return 0 if ddump was cleared; > 0 no saved ddump found
860  */
861 
862 int32_t
863 ocs_clear_saved_ddump(ocs_t *ocs)
864 {
865 	/* if there's a saved ddump, copy to newly allocated textbuf */
866 	if (ocs_textbuf_get_written(&ocs->ddump_saved)) {
867 		ocs_log_debug(ocs, "saved ddump cleared\n");
868 		ocs_textbuf_reset(&ocs->ddump_saved);
869 		return 0;
870 	} else {
871 		ocs_log_debug(ocs, "no saved ddump found\n");
872 		return 1;
873 	}
874 }
875