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