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