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