1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* Copyright 2009 QLogic Corporation */ 23 24 /* 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma ident "Copyright 2009 QLogic Corporation; ql_debug.c" 30 31 /* 32 * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source 33 * 34 * *********************************************************************** 35 * * ** 36 * * NOTICE ** 37 * * COPYRIGHT (C) 1996-2009 QLOGIC CORPORATION ** 38 * * ALL RIGHTS RESERVED ** 39 * * ** 40 * *********************************************************************** 41 * 42 */ 43 44 #include <ql_apps.h> 45 #include <ql_api.h> 46 #include <ql_debug.h> 47 48 static int ql_flash_errlog_store(ql_adapter_state_t *, uint32_t *); 49 int ql_validate_trace_desc(ql_adapter_state_t *ha); 50 char *ql_find_trace_start(ql_adapter_state_t *ha); 51 52 /* 53 * Global Data. 54 */ 55 uint32_t el_message_number = 0; 56 uint32_t ql_enable_ellock = 0; 57 58 extern int getpcstack(pc_t *, int); 59 extern char *kobj_getsymname(uintptr_t, ulong_t *); 60 61 /* 62 * ql_dump_buffer 63 * Outputs buffer. 64 * 65 * Input: 66 * string: Null terminated string (no newline at end). 67 * buffer: buffer address. 68 * wd_size: word size 8 bits 69 * count: number of words. 70 */ 71 void 72 ql_dump_buffer(uint8_t *b8, uint8_t wd_size, uint32_t count) 73 { 74 uint32_t cnt; 75 char str[256], *sp; 76 uint32_t *b32 = (uint32_t *)b8; 77 uint16_t *b16 = (uint16_t *)b8; 78 79 sp = &str[0]; 80 81 switch (wd_size) { 82 case 32: 83 cmn_err(CE_CONT, " 0 4 8 C\n"); 84 cmn_err(CE_CONT, "----------------------------------------\n"); 85 86 for (cnt = 1; cnt <= count; cnt++) { 87 (void) sprintf(sp, "%10x", *b32++); 88 sp += 10; 89 if (cnt % 4 == 0) { 90 cmn_err(CE_CONT, "%s\n", str); 91 sp = &str[0]; 92 } 93 } 94 break; 95 case 16: 96 cmn_err(CE_CONT, " 0 2 4 6 8 A C" 97 " E\n"); 98 cmn_err(CE_CONT, "------------------------------------------" 99 "------\n"); 100 101 for (cnt = 1; cnt <= count; cnt++) { 102 (void) sprintf(sp, "%6x", *b16++); 103 sp += 6; 104 if (cnt % 8 == 0) { 105 cmn_err(CE_CONT, "%s\n", str); 106 sp = &str[0]; 107 } 108 } 109 break; 110 case 8: 111 cmn_err(CE_CONT, " 0 1 2 3 4 5 6 7 8 9 " 112 "A B C D E F\n"); 113 cmn_err(CE_CONT, "---------------------------------" 114 "-------------------------------\n"); 115 116 for (cnt = 1; cnt <= count; cnt++) { 117 (void) sprintf(sp, "%4x", *b8++); 118 sp += 4; 119 if (cnt % 16 == 0) { 120 cmn_err(CE_CONT, "%s\n", str); 121 sp = &str[0]; 122 } 123 } 124 break; 125 default: 126 break; 127 } 128 if (sp != &str[0]) { 129 cmn_err(CE_CONT, "%s\n", str); 130 } 131 } 132 133 /* 134 * ql_el_msg 135 * Extended logging message 136 * 137 * Input: 138 * ha: adapter state pointer. 139 * fn: function name. 140 * ce: level 141 * ...: Variable argument list. 142 * 143 * Context: 144 * Kernel/Interrupt context. 145 */ 146 void 147 ql_el_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...) 148 { 149 uint32_t el_msg_num; 150 char *s, *fmt = 0, *fmt1 = 0; 151 char fmt2[256]; 152 int rval, tmp; 153 int tracing = 0; 154 va_list vl; 155 156 /* Tracing is the default but it can be disabled. */ 157 if ((CFG_IST(ha, CFG_DISABLE_EXTENDED_LOGGING_TRACE) == 0) && 158 (rval = ql_validate_trace_desc(ha) == DDI_SUCCESS)) { 159 tracing = 1; 160 161 TRACE_BUFFER_LOCK(ha); 162 163 /* 164 * Ensure enough space for the string. Wrap to 165 * start when default message allocation size 166 * would overrun the end. 167 */ 168 if ((ha->el_trace_desc->next + EL_BUFFER_RESERVE) >= 169 ha->el_trace_desc->trace_buffer_size) { 170 fmt = ha->el_trace_desc->trace_buffer; 171 ha->el_trace_desc->next = 0; 172 } else { 173 fmt = ha->el_trace_desc->trace_buffer + 174 ha->el_trace_desc->next; 175 } 176 } 177 /* if no buffer use the stack */ 178 if (fmt == NULL) { 179 fmt = fmt2; 180 } 181 182 va_start(vl, ce); 183 184 s = va_arg(vl, char *); 185 186 if (ql_enable_ellock) { 187 /* 188 * Used when messages are *maybe* being lost. Adds 189 * a unique number to the message so one can see if 190 * any messages have been dropped. NB: This slows 191 * down the driver, which may make the issue disappear. 192 */ 193 GLOBAL_EL_LOCK(); 194 el_msg_num = ++el_message_number; 195 GLOBAL_EL_UNLOCK(); 196 197 rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE, 198 QL_BANG "QEL%d %s(%d,%d): %s, ", el_msg_num, QL_NAME, 199 ha->instance, ha->vp_index, fn); 200 fmt1 = fmt + rval; 201 tmp = (int)vsnprintf(fmt1, 202 (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); 203 rval += tmp; 204 } else { 205 rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE, 206 QL_BANG "QEL %s(%d,%d): %s, ", QL_NAME, ha->instance, 207 ha->vp_index, fn); 208 fmt1 = fmt + rval; 209 tmp = (int)vsnprintf(fmt1, 210 (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); 211 rval += tmp; 212 } 213 214 /* 215 * Calculate the offset where the next message will go, 216 * skipping the NULL. 217 */ 218 if (tracing) { 219 uint16_t next = (uint16_t)(rval += 1); 220 ha->el_trace_desc->next += next; 221 TRACE_BUFFER_UNLOCK(ha); 222 } 223 224 if (CFG_IST(ha, CFG_ENABLE_EXTENDED_LOGGING)) { 225 cmn_err(ce, fmt); 226 } 227 228 va_end(vl); 229 } 230 231 /* 232 * ql_el_msg 233 * Extended logging message 234 * 235 * Input: 236 * ha: adapter state pointer. 237 * fn: function name. 238 * ce: level 239 * ...: Variable argument list. 240 * 241 * Context: 242 * Kernel/Interrupt context. 243 */ 244 void 245 ql_dbg_msg(const char *fn, int ce, ...) 246 { 247 uint32_t el_msg_num; 248 char *s; 249 char fmt[256]; 250 va_list vl; 251 252 va_start(vl, ce); 253 254 s = va_arg(vl, char *); 255 256 if (ql_enable_ellock) { 257 /* 258 * Used when messages are *maybe* being lost. Adds 259 * a unique number to the message to one can see if 260 * any messages have been dropped. NB: This slows 261 * down the driver, which may make the issue disappear. 262 */ 263 GLOBAL_EL_LOCK(); 264 el_msg_num = ++el_message_number; 265 GLOBAL_EL_UNLOCK(); 266 (void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP%d: %s %s, %s", 267 el_msg_num, QL_NAME, fn, s); 268 } else { 269 (void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP: %s %s, %s", 270 QL_NAME, fn, s); 271 } 272 273 vcmn_err(ce, fmt, vl); 274 275 va_end(vl); 276 } 277 278 /* 279 * ql_stacktrace 280 * Prints out current stack 281 * 282 * Input: 283 * ha: adapter state pointer. 284 * 285 * Context: 286 * Kernel/Interrupt context. 287 */ 288 void 289 ql_stacktrace(ql_adapter_state_t *ha) 290 { 291 int depth, i; 292 pc_t pcstack[DEBUG_STK_DEPTH]; 293 char *sym = NULL; 294 ulong_t off; 295 296 depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH); 297 298 cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 299 ha->vp_index); 300 for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) { 301 sym = kobj_getsymname((uintptr_t)pcstack[i], &off); 302 303 if (sym == NULL) { 304 cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME, 305 ha->instance, ha->vp_index); 306 } else { 307 cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME, 308 ha->instance, ha->vp_index, sym ? sym : "?", off); 309 } 310 } 311 cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 312 ha->vp_index); 313 } 314 315 /* 316 * ql_flash_errlog 317 * Adds error to flash error log. 318 * Entry Layout: 319 * uint32_t TimeStamp; 320 * uint16_t CodeData[4]; 321 * 322 * Input: 323 * ha: adapter state pointer. 324 * code: Error code 325 * d1-d3: Error code data 326 * 327 * Returns: 328 * ql local function return status code. 329 * 330 * Context: 331 * Kernel/Interrupt context. 332 */ 333 int 334 ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1, 335 uint16_t d2, uint16_t d3) 336 { 337 char *s; 338 uint32_t marker[2], fdata[2], faddr; 339 int rval; 340 341 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 342 343 if (ha->flash_errlog_start == 0) { 344 return (QL_NOT_SUPPORTED); 345 } 346 347 EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3); 348 349 /* 350 * If marker not already found, locate or write marker. 351 */ 352 if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 353 354 /* Create marker. */ 355 marker[0] = CHAR_TO_LONG(ha->fw_subminor_version, 356 ha->fw_minor_version, ha->fw_major_version, 'S'); 357 358 /* 359 * Version should be of the format: YYYYMMDD-v.vv 360 */ 361 if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) { 362 s = &QL_VERSION[9]; 363 } else { 364 s = QL_VERSION; 365 } 366 367 for (marker[1] = 0; *s != '\0'; s++) { 368 if (*s >= '0' && *s <= '9') { 369 marker[1] <<= 4; 370 marker[1] |= *s - '0'; 371 } else if (*s != '.') { 372 break; 373 } 374 } 375 376 /* Locate marker. */ 377 ha->flash_errlog_ptr = ha->flash_errlog_start; 378 for (;;) { 379 faddr = ha->flash_data_addr | ha->flash_errlog_ptr; 380 (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 381 (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 382 if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) { 383 break; 384 } 385 (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 386 (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 387 ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 388 if (ha->flash_errlog_ptr >= 389 ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 390 EL(ha, "log full\n"); 391 return (QL_MEMORY_FULL); 392 } 393 if (fdata[0] == marker[0] && fdata[1] == marker[1]) { 394 ha->flags |= FLASH_ERRLOG_MARKER; 395 break; 396 } 397 } 398 399 /* No marker, write it. */ 400 if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 401 ha->flags |= FLASH_ERRLOG_MARKER; 402 rval = ql_flash_errlog_store(ha, marker); 403 if (rval != QL_SUCCESS) { 404 EL(ha, "failed marker write=%xh\n", rval); 405 return (rval); 406 } 407 } 408 } 409 410 /* 411 * Store error. 412 */ 413 fdata[0] = SHORT_TO_LONG(d1, code); 414 fdata[1] = SHORT_TO_LONG(d3, d2); 415 rval = ql_flash_errlog_store(ha, fdata); 416 if (rval != QL_SUCCESS) { 417 EL(ha, "failed error write=%xh\n", rval); 418 } else { 419 /*EMPTY*/ 420 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 421 } 422 423 return (rval); 424 } 425 426 /* 427 * ql_flash_errlog_store 428 * Stores error to flash. 429 * Entry Layout: 430 * uint32_t TimeStamp; 431 * uint16_t CodeData[4]; 432 * 433 * Input: 434 * ha: adapter state pointer. 435 * fdata: Error code plus data. 436 * ha->flash_errlog_ptr: Current Flash error pointer. 437 * 438 * Output: 439 * ha->flash_errlog_ptr: updated pointer. 440 * 441 * Returns: 442 * ql local function return status code. 443 * 444 * Context: 445 * Kernel/Interrupt context. 446 */ 447 static int 448 ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata) 449 { 450 int rval; 451 uint64_t time; 452 uint32_t d1, d2, faddr; 453 454 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 455 456 /* Locate first empty entry */ 457 for (;;) { 458 if (ha->flash_errlog_ptr >= 459 ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 460 EL(ha, "log full\n"); 461 return (QL_MEMORY_FULL); 462 } 463 464 faddr = ha->flash_data_addr | ha->flash_errlog_ptr; 465 ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 466 (void) ql_24xx_read_flash(ha, faddr, &d1); 467 (void) ql_24xx_read_flash(ha, faddr + 1, &d2); 468 if (d1 == 0xffffffff && d2 == 0xffffffff) { 469 (void) drv_getparm(TIME, &time); 470 471 /* Enable flash write. */ 472 if ((rval = ql_24xx_unprotect_flash(ha)) != 473 QL_SUCCESS) { 474 EL(ha, "unprotect_flash failed, rval=%xh\n", 475 rval); 476 return (rval); 477 } 478 479 (void) ql_24xx_write_flash(ha, faddr++, LSD(time)); 480 (void) ql_24xx_write_flash(ha, faddr++, MSD(time)); 481 (void) ql_24xx_write_flash(ha, faddr++, *fdata++); 482 (void) ql_24xx_write_flash(ha, faddr++, *fdata); 483 484 /* Enable flash write-protection. */ 485 ql_24xx_protect_flash(ha); 486 break; 487 } 488 } 489 490 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 491 492 return (QL_SUCCESS); 493 } 494 495 /* 496 * ql_dump_el_trace_buffer 497 * Outputs extended logging trace buffer. 498 * 499 * Input: 500 * ha: adapter state pointer. 501 */ 502 void 503 ql_dump_el_trace_buffer(ql_adapter_state_t *ha) 504 { 505 char *dump_start = NULL; 506 char *dump_current = NULL; 507 char *trace_start; 508 char *trace_end; 509 int wrapped = 0; 510 int rval; 511 512 TRACE_BUFFER_LOCK(ha); 513 514 rval = ql_validate_trace_desc(ha); 515 if (rval != NULL) { 516 cmn_err(CE_CONT, "%s(%d) Dump EL trace - invalid desc\n", 517 QL_NAME, ha->instance); 518 } else if ((dump_start = ql_find_trace_start(ha)) != NULL) { 519 dump_current = dump_start; 520 trace_start = ha->el_trace_desc->trace_buffer; 521 trace_end = trace_start + 522 ha->el_trace_desc->trace_buffer_size; 523 524 cmn_err(CE_CONT, "%s(%d) Dump EL trace - start %p %p\n", 525 QL_NAME, ha->instance, 526 (void *)dump_start, (void *)trace_start); 527 528 while (((uintptr_t)dump_current - (uintptr_t)trace_start) <= 529 (uintptr_t)ha->el_trace_desc->trace_buffer_size) { 530 /* Show it... */ 531 cmn_err(CE_CONT, "%p - %s", (void *)dump_current, 532 dump_current); 533 /* Make the next the current */ 534 dump_current += (strlen(dump_current) + 1); 535 /* check for wrap */ 536 if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) { 537 dump_current = trace_start; 538 wrapped = 1; 539 } else if (wrapped) { 540 /* Don't go past next. */ 541 if ((trace_start + ha->el_trace_desc->next) <= 542 dump_current) { 543 break; 544 } 545 } else if (*dump_current == NULL) { 546 break; 547 } 548 } 549 } 550 TRACE_BUFFER_UNLOCK(ha); 551 } 552 553 /* 554 * ql_validate_trace_desc 555 * Ensures the extended logging trace descriptor is good 556 * 557 * Input: 558 * ha: adapter state pointer. 559 * 560 * Returns: 561 * ql local function return status code. 562 */ 563 int 564 ql_validate_trace_desc(ql_adapter_state_t *ha) 565 { 566 int rval = DDI_SUCCESS; 567 568 if (ha->el_trace_desc == NULL) { 569 rval = DDI_FAILURE; 570 } else if (ha->el_trace_desc->trace_buffer == NULL) { 571 rval = DDI_FAILURE; 572 } 573 return (rval); 574 } 575 576 /* 577 * ql_find_trace_start 578 * Locate the oldest extended logging trace entry. 579 * 580 * Input: 581 * ha: adapter state pointer. 582 * 583 * Returns: 584 * Pointer to a string. 585 * 586 * Context: 587 * Kernel/Interrupt context. 588 */ 589 char * 590 ql_find_trace_start(ql_adapter_state_t *ha) 591 { 592 char *trace_start = 0; 593 char *trace_next = 0; 594 595 trace_next = ha->el_trace_desc->trace_buffer + ha->el_trace_desc->next; 596 597 /* 598 * if the buffer has not wrapped next will point at a null so 599 * start is the beginning of the buffer. if next points at a char 600 * then we must traverse the buffer until a null is detected and 601 * that will be the beginning of the oldest whole object in the buffer 602 * which is the start. 603 */ 604 605 if ((trace_next + EL_BUFFER_RESERVE) >= 606 (ha->el_trace_desc->trace_buffer + 607 ha->el_trace_desc->trace_buffer_size)) { 608 trace_start = ha->el_trace_desc->trace_buffer; 609 } else if (*trace_next != NULL) { 610 trace_start = trace_next + (strlen(trace_next) + 1); 611 } else { 612 trace_start = ha->el_trace_desc->trace_buffer; 613 } 614 return (trace_start); 615 } 616