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