1fcf3ce44SJohn Forte /* 2fcf3ce44SJohn Forte * CDDL HEADER START 3fcf3ce44SJohn Forte * 4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7fcf3ce44SJohn Forte * 8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11fcf3ce44SJohn Forte * and limitations under the License. 12fcf3ce44SJohn Forte * 13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18fcf3ce44SJohn Forte * 19fcf3ce44SJohn Forte * CDDL HEADER END 20fcf3ce44SJohn Forte */ 21fcf3ce44SJohn Forte 2216dd44c2SDaniel Beauregard /* Copyright 2009 QLogic Corporation */ 23fcf3ce44SJohn Forte 24fcf3ce44SJohn Forte /* 2516dd44c2SDaniel Beauregard * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26fcf3ce44SJohn Forte * Use is subject to license terms. 27fcf3ce44SJohn Forte */ 28fcf3ce44SJohn Forte 2916dd44c2SDaniel Beauregard #pragma ident "Copyright 2009 QLogic Corporation; ql_debug.c" 30fcf3ce44SJohn Forte 31fcf3ce44SJohn Forte /* 32fcf3ce44SJohn Forte * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source 33fcf3ce44SJohn Forte * 34fcf3ce44SJohn Forte * *********************************************************************** 35fcf3ce44SJohn Forte * * ** 36fcf3ce44SJohn Forte * * NOTICE ** 3716dd44c2SDaniel Beauregard * * COPYRIGHT (C) 1996-2009 QLOGIC CORPORATION ** 38fcf3ce44SJohn Forte * * ALL RIGHTS RESERVED ** 39fcf3ce44SJohn Forte * * ** 40fcf3ce44SJohn Forte * *********************************************************************** 41fcf3ce44SJohn Forte * 42fcf3ce44SJohn Forte */ 43fcf3ce44SJohn Forte 44fcf3ce44SJohn Forte #include <ql_apps.h> 45fcf3ce44SJohn Forte #include <ql_api.h> 46fcf3ce44SJohn Forte #include <ql_debug.h> 47fcf3ce44SJohn Forte 48fcf3ce44SJohn Forte static int ql_flash_errlog_store(ql_adapter_state_t *, uint32_t *); 4916dd44c2SDaniel Beauregard int ql_validate_trace_desc(ql_adapter_state_t *ha); 5016dd44c2SDaniel Beauregard char *ql_find_trace_start(ql_adapter_state_t *ha); 51fcf3ce44SJohn Forte 52fcf3ce44SJohn Forte /* 53fcf3ce44SJohn Forte * Global Data. 54fcf3ce44SJohn Forte */ 55fcf3ce44SJohn Forte uint32_t el_message_number = 0; 56fcf3ce44SJohn Forte uint32_t ql_enable_ellock = 0; 57fcf3ce44SJohn Forte 58fcf3ce44SJohn Forte extern int getpcstack(pc_t *, int); 59fcf3ce44SJohn Forte extern char *kobj_getsymname(uintptr_t, ulong_t *); 60fcf3ce44SJohn Forte 61fcf3ce44SJohn Forte /* 62fcf3ce44SJohn Forte * ql_dump_buffer 63fcf3ce44SJohn Forte * Outputs buffer. 64fcf3ce44SJohn Forte * 65fcf3ce44SJohn Forte * Input: 66fcf3ce44SJohn Forte * string: Null terminated string (no newline at end). 67fcf3ce44SJohn Forte * buffer: buffer address. 68fcf3ce44SJohn Forte * wd_size: word size 8 bits 69fcf3ce44SJohn Forte * count: number of words. 70fcf3ce44SJohn Forte */ 71fcf3ce44SJohn Forte void 72fcf3ce44SJohn Forte ql_dump_buffer(uint8_t *b8, uint8_t wd_size, uint32_t count) 73fcf3ce44SJohn Forte { 74fcf3ce44SJohn Forte uint32_t cnt; 75fcf3ce44SJohn Forte char str[256], *sp; 76fcf3ce44SJohn Forte uint32_t *b32 = (uint32_t *)b8; 77fcf3ce44SJohn Forte uint16_t *b16 = (uint16_t *)b8; 78fcf3ce44SJohn Forte 79fcf3ce44SJohn Forte sp = &str[0]; 80fcf3ce44SJohn Forte 81fcf3ce44SJohn Forte switch (wd_size) { 82fcf3ce44SJohn Forte case 32: 83fcf3ce44SJohn Forte cmn_err(CE_CONT, " 0 4 8 C\n"); 84fcf3ce44SJohn Forte cmn_err(CE_CONT, "----------------------------------------\n"); 85fcf3ce44SJohn Forte 86fcf3ce44SJohn Forte for (cnt = 1; cnt <= count; cnt++) { 87fcf3ce44SJohn Forte (void) sprintf(sp, "%10x", *b32++); 88fcf3ce44SJohn Forte sp += 10; 89fcf3ce44SJohn Forte if (cnt % 4 == 0) { 90fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s\n", str); 91fcf3ce44SJohn Forte sp = &str[0]; 92fcf3ce44SJohn Forte } 93fcf3ce44SJohn Forte } 94fcf3ce44SJohn Forte break; 95fcf3ce44SJohn Forte case 16: 96fcf3ce44SJohn Forte cmn_err(CE_CONT, " 0 2 4 6 8 A C" 97fcf3ce44SJohn Forte " E\n"); 98fcf3ce44SJohn Forte cmn_err(CE_CONT, "------------------------------------------" 99fcf3ce44SJohn Forte "------\n"); 100fcf3ce44SJohn Forte 101fcf3ce44SJohn Forte for (cnt = 1; cnt <= count; cnt++) { 102fcf3ce44SJohn Forte (void) sprintf(sp, "%6x", *b16++); 103fcf3ce44SJohn Forte sp += 6; 104fcf3ce44SJohn Forte if (cnt % 8 == 0) { 105fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s\n", str); 106fcf3ce44SJohn Forte sp = &str[0]; 107fcf3ce44SJohn Forte } 108fcf3ce44SJohn Forte } 109fcf3ce44SJohn Forte break; 110fcf3ce44SJohn Forte case 8: 111fcf3ce44SJohn Forte cmn_err(CE_CONT, " 0 1 2 3 4 5 6 7 8 9 " 112fcf3ce44SJohn Forte "A B C D E F\n"); 113fcf3ce44SJohn Forte cmn_err(CE_CONT, "---------------------------------" 114fcf3ce44SJohn Forte "-------------------------------\n"); 115fcf3ce44SJohn Forte 116fcf3ce44SJohn Forte for (cnt = 1; cnt <= count; cnt++) { 117fcf3ce44SJohn Forte (void) sprintf(sp, "%4x", *b8++); 118fcf3ce44SJohn Forte sp += 4; 119fcf3ce44SJohn Forte if (cnt % 16 == 0) { 120fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s\n", str); 121fcf3ce44SJohn Forte sp = &str[0]; 122fcf3ce44SJohn Forte } 123fcf3ce44SJohn Forte } 124fcf3ce44SJohn Forte break; 125fcf3ce44SJohn Forte default: 126fcf3ce44SJohn Forte break; 127fcf3ce44SJohn Forte } 128fcf3ce44SJohn Forte if (sp != &str[0]) { 129fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s\n", str); 130fcf3ce44SJohn Forte } 131fcf3ce44SJohn Forte } 132fcf3ce44SJohn Forte 133fcf3ce44SJohn Forte /* 134fcf3ce44SJohn Forte * ql_el_msg 135fcf3ce44SJohn Forte * Extended logging message 136fcf3ce44SJohn Forte * 137fcf3ce44SJohn Forte * Input: 138fcf3ce44SJohn Forte * ha: adapter state pointer. 139fcf3ce44SJohn Forte * fn: function name. 140fcf3ce44SJohn Forte * ce: level 141fcf3ce44SJohn Forte * ...: Variable argument list. 142fcf3ce44SJohn Forte * 143fcf3ce44SJohn Forte * Context: 144fcf3ce44SJohn Forte * Kernel/Interrupt context. 145fcf3ce44SJohn Forte */ 146fcf3ce44SJohn Forte void 147fcf3ce44SJohn Forte ql_el_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...) 148fcf3ce44SJohn Forte { 149fcf3ce44SJohn Forte uint32_t el_msg_num; 15016dd44c2SDaniel Beauregard char *s, *fmt = 0, *fmt1 = 0; 15116dd44c2SDaniel Beauregard char fmt2[256]; 15216dd44c2SDaniel Beauregard int rval, tmp; 15316dd44c2SDaniel Beauregard int tracing = 0; 154fcf3ce44SJohn Forte va_list vl; 155fcf3ce44SJohn Forte 15616dd44c2SDaniel Beauregard /* Tracing is the default but it can be disabled. */ 1575dfd244aSDaniel Beauregard if ((CFG_IST(ha, CFG_DISABLE_EXTENDED_LOGGING_TRACE) == 0) && 15816dd44c2SDaniel Beauregard (rval = ql_validate_trace_desc(ha) == DDI_SUCCESS)) { 15916dd44c2SDaniel Beauregard tracing = 1; 16016dd44c2SDaniel Beauregard 16116dd44c2SDaniel Beauregard TRACE_BUFFER_LOCK(ha); 16216dd44c2SDaniel Beauregard 16316dd44c2SDaniel Beauregard /* 16416dd44c2SDaniel Beauregard * Ensure enough space for the string. Wrap to 16516dd44c2SDaniel Beauregard * start when default message allocation size 16616dd44c2SDaniel Beauregard * would overrun the end. 16716dd44c2SDaniel Beauregard */ 16816dd44c2SDaniel Beauregard if ((ha->el_trace_desc->next + EL_BUFFER_RESERVE) >= 16916dd44c2SDaniel Beauregard ha->el_trace_desc->trace_buffer_size) { 17016dd44c2SDaniel Beauregard fmt = ha->el_trace_desc->trace_buffer; 17116dd44c2SDaniel Beauregard ha->el_trace_desc->next = 0; 17216dd44c2SDaniel Beauregard } else { 17316dd44c2SDaniel Beauregard fmt = ha->el_trace_desc->trace_buffer + 17416dd44c2SDaniel Beauregard ha->el_trace_desc->next; 17516dd44c2SDaniel Beauregard } 17616dd44c2SDaniel Beauregard } 17716dd44c2SDaniel Beauregard /* if no buffer use the stack */ 17816dd44c2SDaniel Beauregard if (fmt == NULL) { 17916dd44c2SDaniel Beauregard fmt = fmt2; 18016dd44c2SDaniel Beauregard } 18116dd44c2SDaniel Beauregard 182fcf3ce44SJohn Forte va_start(vl, ce); 183fcf3ce44SJohn Forte 184fcf3ce44SJohn Forte s = va_arg(vl, char *); 185fcf3ce44SJohn Forte 186fcf3ce44SJohn Forte if (ql_enable_ellock) { 187fcf3ce44SJohn Forte /* 188fcf3ce44SJohn Forte * Used when messages are *maybe* being lost. Adds 18916dd44c2SDaniel Beauregard * a unique number to the message so one can see if 190fcf3ce44SJohn Forte * any messages have been dropped. NB: This slows 191fcf3ce44SJohn Forte * down the driver, which may make the issue disappear. 192fcf3ce44SJohn Forte */ 193fcf3ce44SJohn Forte GLOBAL_EL_LOCK(); 194fcf3ce44SJohn Forte el_msg_num = ++el_message_number; 195fcf3ce44SJohn Forte GLOBAL_EL_UNLOCK(); 196fcf3ce44SJohn Forte 19716dd44c2SDaniel Beauregard rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE, 1985dfd244aSDaniel Beauregard QL_BANG "QEL%d %s(%d,%d): %s, ", el_msg_num, QL_NAME, 1995dfd244aSDaniel Beauregard ha->instance, ha->vp_index, fn); 20016dd44c2SDaniel Beauregard fmt1 = fmt + rval; 20116dd44c2SDaniel Beauregard tmp = (int)vsnprintf(fmt1, 20216dd44c2SDaniel Beauregard (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); 20316dd44c2SDaniel Beauregard rval += tmp; 204fcf3ce44SJohn Forte } else { 20516dd44c2SDaniel Beauregard rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE, 20616dd44c2SDaniel Beauregard QL_BANG "QEL %s(%d,%d): %s, ", QL_NAME, ha->instance, 20716dd44c2SDaniel Beauregard ha->vp_index, fn); 20816dd44c2SDaniel Beauregard fmt1 = fmt + rval; 20916dd44c2SDaniel Beauregard tmp = (int)vsnprintf(fmt1, 21016dd44c2SDaniel Beauregard (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); 21116dd44c2SDaniel Beauregard rval += tmp; 21216dd44c2SDaniel Beauregard } 21316dd44c2SDaniel Beauregard 21416dd44c2SDaniel Beauregard /* 21516dd44c2SDaniel Beauregard * Calculate the offset where the next message will go, 21616dd44c2SDaniel Beauregard * skipping the NULL. 21716dd44c2SDaniel Beauregard */ 21816dd44c2SDaniel Beauregard if (tracing) { 219*7a2b99c0SDaniel Beauregard uint16_t next = (uint16_t)(rval += 1); 220*7a2b99c0SDaniel Beauregard ha->el_trace_desc->next += next; 22116dd44c2SDaniel Beauregard TRACE_BUFFER_UNLOCK(ha); 22216dd44c2SDaniel Beauregard } 22316dd44c2SDaniel Beauregard 2245dfd244aSDaniel Beauregard if (CFG_IST(ha, CFG_ENABLE_EXTENDED_LOGGING)) { 22516dd44c2SDaniel Beauregard cmn_err(ce, fmt); 22616dd44c2SDaniel Beauregard } 22716dd44c2SDaniel Beauregard 22816dd44c2SDaniel Beauregard va_end(vl); 22916dd44c2SDaniel Beauregard } 23016dd44c2SDaniel Beauregard 23116dd44c2SDaniel Beauregard /* 23216dd44c2SDaniel Beauregard * ql_el_msg 23316dd44c2SDaniel Beauregard * Extended logging message 23416dd44c2SDaniel Beauregard * 23516dd44c2SDaniel Beauregard * Input: 23616dd44c2SDaniel Beauregard * ha: adapter state pointer. 23716dd44c2SDaniel Beauregard * fn: function name. 23816dd44c2SDaniel Beauregard * ce: level 23916dd44c2SDaniel Beauregard * ...: Variable argument list. 24016dd44c2SDaniel Beauregard * 24116dd44c2SDaniel Beauregard * Context: 24216dd44c2SDaniel Beauregard * Kernel/Interrupt context. 24316dd44c2SDaniel Beauregard */ 24416dd44c2SDaniel Beauregard void 24516dd44c2SDaniel Beauregard ql_dbg_msg(const char *fn, int ce, ...) 24616dd44c2SDaniel Beauregard { 24716dd44c2SDaniel Beauregard uint32_t el_msg_num; 24816dd44c2SDaniel Beauregard char *s; 24916dd44c2SDaniel Beauregard char fmt[256]; 25016dd44c2SDaniel Beauregard va_list vl; 25116dd44c2SDaniel Beauregard 25216dd44c2SDaniel Beauregard va_start(vl, ce); 25316dd44c2SDaniel Beauregard 25416dd44c2SDaniel Beauregard s = va_arg(vl, char *); 25516dd44c2SDaniel Beauregard 25616dd44c2SDaniel Beauregard if (ql_enable_ellock) { 25716dd44c2SDaniel Beauregard /* 25816dd44c2SDaniel Beauregard * Used when messages are *maybe* being lost. Adds 25916dd44c2SDaniel Beauregard * a unique number to the message to one can see if 26016dd44c2SDaniel Beauregard * any messages have been dropped. NB: This slows 26116dd44c2SDaniel Beauregard * down the driver, which may make the issue disappear. 26216dd44c2SDaniel Beauregard */ 26316dd44c2SDaniel Beauregard GLOBAL_EL_LOCK(); 26416dd44c2SDaniel Beauregard el_msg_num = ++el_message_number; 26516dd44c2SDaniel Beauregard GLOBAL_EL_UNLOCK(); 26616dd44c2SDaniel Beauregard (void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP%d: %s %s, %s", 26716dd44c2SDaniel Beauregard el_msg_num, QL_NAME, fn, s); 26816dd44c2SDaniel Beauregard } else { 26916dd44c2SDaniel Beauregard (void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP: %s %s, %s", 27016dd44c2SDaniel Beauregard QL_NAME, fn, s); 271fcf3ce44SJohn Forte } 272fcf3ce44SJohn Forte 273fcf3ce44SJohn Forte vcmn_err(ce, fmt, vl); 274fcf3ce44SJohn Forte 275fcf3ce44SJohn Forte va_end(vl); 276fcf3ce44SJohn Forte } 277fcf3ce44SJohn Forte 278fcf3ce44SJohn Forte /* 279fcf3ce44SJohn Forte * ql_stacktrace 280fcf3ce44SJohn Forte * Prints out current stack 281fcf3ce44SJohn Forte * 282fcf3ce44SJohn Forte * Input: 283fcf3ce44SJohn Forte * ha: adapter state pointer. 284fcf3ce44SJohn Forte * 285fcf3ce44SJohn Forte * Context: 286fcf3ce44SJohn Forte * Kernel/Interrupt context. 287fcf3ce44SJohn Forte */ 288fcf3ce44SJohn Forte void 289fcf3ce44SJohn Forte ql_stacktrace(ql_adapter_state_t *ha) 290fcf3ce44SJohn Forte { 291fcf3ce44SJohn Forte int depth, i; 292fcf3ce44SJohn Forte pc_t pcstack[DEBUG_STK_DEPTH]; 293fcf3ce44SJohn Forte char *sym = NULL; 294fcf3ce44SJohn Forte ulong_t off; 295fcf3ce44SJohn Forte 296fcf3ce44SJohn Forte depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH); 297fcf3ce44SJohn Forte 298fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 299fcf3ce44SJohn Forte ha->vp_index); 300fcf3ce44SJohn Forte for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) { 301fcf3ce44SJohn Forte sym = kobj_getsymname((uintptr_t)pcstack[i], &off); 302fcf3ce44SJohn Forte 303fcf3ce44SJohn Forte if (sym == NULL) { 304fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME, 305fcf3ce44SJohn Forte ha->instance, ha->vp_index); 306fcf3ce44SJohn Forte } else { 307fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME, 308fcf3ce44SJohn Forte ha->instance, ha->vp_index, sym ? sym : "?", off); 309fcf3ce44SJohn Forte } 310fcf3ce44SJohn Forte } 311fcf3ce44SJohn Forte cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 312fcf3ce44SJohn Forte ha->vp_index); 313fcf3ce44SJohn Forte } 314fcf3ce44SJohn Forte 315fcf3ce44SJohn Forte /* 316fcf3ce44SJohn Forte * ql_flash_errlog 317fcf3ce44SJohn Forte * Adds error to flash error log. 318fcf3ce44SJohn Forte * Entry Layout: 319fcf3ce44SJohn Forte * uint32_t TimeStamp; 320fcf3ce44SJohn Forte * uint16_t CodeData[4]; 321fcf3ce44SJohn Forte * 322fcf3ce44SJohn Forte * Input: 323fcf3ce44SJohn Forte * ha: adapter state pointer. 324fcf3ce44SJohn Forte * code: Error code 325fcf3ce44SJohn Forte * d1-d3: Error code data 326fcf3ce44SJohn Forte * 327fcf3ce44SJohn Forte * Returns: 328fcf3ce44SJohn Forte * ql local function return status code. 329fcf3ce44SJohn Forte * 330fcf3ce44SJohn Forte * Context: 331fcf3ce44SJohn Forte * Kernel/Interrupt context. 332fcf3ce44SJohn Forte */ 333fcf3ce44SJohn Forte int 334fcf3ce44SJohn Forte ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1, 335fcf3ce44SJohn Forte uint16_t d2, uint16_t d3) 336fcf3ce44SJohn Forte { 337fcf3ce44SJohn Forte char *s; 338fcf3ce44SJohn Forte uint32_t marker[2], fdata[2], faddr; 339fcf3ce44SJohn Forte int rval; 340fcf3ce44SJohn Forte 3415dfd244aSDaniel Beauregard QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 342fcf3ce44SJohn Forte 343fcf3ce44SJohn Forte if (ha->flash_errlog_start == 0) { 344fcf3ce44SJohn Forte return (QL_NOT_SUPPORTED); 345fcf3ce44SJohn Forte } 346fcf3ce44SJohn Forte 347fcf3ce44SJohn Forte EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3); 348fcf3ce44SJohn Forte 349fcf3ce44SJohn Forte /* 350fcf3ce44SJohn Forte * If marker not already found, locate or write marker. 351fcf3ce44SJohn Forte */ 352fcf3ce44SJohn Forte if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 353fcf3ce44SJohn Forte 354fcf3ce44SJohn Forte /* Create marker. */ 355fcf3ce44SJohn Forte marker[0] = CHAR_TO_LONG(ha->fw_subminor_version, 356fcf3ce44SJohn Forte ha->fw_minor_version, ha->fw_major_version, 'S'); 357fcf3ce44SJohn Forte 358fcf3ce44SJohn Forte /* 359fcf3ce44SJohn Forte * Version should be of the format: YYYYMMDD-v.vv 360fcf3ce44SJohn Forte */ 361fcf3ce44SJohn Forte if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) { 362fcf3ce44SJohn Forte s = &QL_VERSION[9]; 363fcf3ce44SJohn Forte } else { 364fcf3ce44SJohn Forte s = QL_VERSION; 365fcf3ce44SJohn Forte } 366fcf3ce44SJohn Forte 367fcf3ce44SJohn Forte for (marker[1] = 0; *s != '\0'; s++) { 368fcf3ce44SJohn Forte if (*s >= '0' && *s <= '9') { 369fcf3ce44SJohn Forte marker[1] <<= 4; 370fcf3ce44SJohn Forte marker[1] |= *s - '0'; 371fcf3ce44SJohn Forte } else if (*s != '.') { 372fcf3ce44SJohn Forte break; 373fcf3ce44SJohn Forte } 374fcf3ce44SJohn Forte } 375fcf3ce44SJohn Forte 376fcf3ce44SJohn Forte /* Locate marker. */ 377fcf3ce44SJohn Forte ha->flash_errlog_ptr = ha->flash_errlog_start; 378fcf3ce44SJohn Forte for (;;) { 3795dfd244aSDaniel Beauregard faddr = ha->flash_data_addr | ha->flash_errlog_ptr; 380fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 381fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 382fcf3ce44SJohn Forte if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) { 383fcf3ce44SJohn Forte break; 384fcf3ce44SJohn Forte } 385fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 386fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 387fcf3ce44SJohn Forte ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 388fcf3ce44SJohn Forte if (ha->flash_errlog_ptr >= 389fcf3ce44SJohn Forte ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 390fcf3ce44SJohn Forte EL(ha, "log full\n"); 391fcf3ce44SJohn Forte return (QL_MEMORY_FULL); 392fcf3ce44SJohn Forte } 393fcf3ce44SJohn Forte if (fdata[0] == marker[0] && fdata[1] == marker[1]) { 394fcf3ce44SJohn Forte ha->flags |= FLASH_ERRLOG_MARKER; 395fcf3ce44SJohn Forte break; 396fcf3ce44SJohn Forte } 397fcf3ce44SJohn Forte } 398fcf3ce44SJohn Forte 399fcf3ce44SJohn Forte /* No marker, write it. */ 400fcf3ce44SJohn Forte if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 401fcf3ce44SJohn Forte ha->flags |= FLASH_ERRLOG_MARKER; 402fcf3ce44SJohn Forte rval = ql_flash_errlog_store(ha, marker); 403fcf3ce44SJohn Forte if (rval != QL_SUCCESS) { 404fcf3ce44SJohn Forte EL(ha, "failed marker write=%xh\n", rval); 405fcf3ce44SJohn Forte return (rval); 406fcf3ce44SJohn Forte } 407fcf3ce44SJohn Forte } 408fcf3ce44SJohn Forte } 409fcf3ce44SJohn Forte 410fcf3ce44SJohn Forte /* 411fcf3ce44SJohn Forte * Store error. 412fcf3ce44SJohn Forte */ 413fcf3ce44SJohn Forte fdata[0] = SHORT_TO_LONG(d1, code); 414fcf3ce44SJohn Forte fdata[1] = SHORT_TO_LONG(d3, d2); 415fcf3ce44SJohn Forte rval = ql_flash_errlog_store(ha, fdata); 416fcf3ce44SJohn Forte if (rval != QL_SUCCESS) { 417fcf3ce44SJohn Forte EL(ha, "failed error write=%xh\n", rval); 418fcf3ce44SJohn Forte } else { 419fcf3ce44SJohn Forte /*EMPTY*/ 4205dfd244aSDaniel Beauregard QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 421fcf3ce44SJohn Forte } 422fcf3ce44SJohn Forte 423fcf3ce44SJohn Forte return (rval); 424fcf3ce44SJohn Forte } 425fcf3ce44SJohn Forte 426fcf3ce44SJohn Forte /* 427fcf3ce44SJohn Forte * ql_flash_errlog_store 428fcf3ce44SJohn Forte * Stores error to flash. 429fcf3ce44SJohn Forte * Entry Layout: 430fcf3ce44SJohn Forte * uint32_t TimeStamp; 431fcf3ce44SJohn Forte * uint16_t CodeData[4]; 432fcf3ce44SJohn Forte * 433fcf3ce44SJohn Forte * Input: 434fcf3ce44SJohn Forte * ha: adapter state pointer. 435fcf3ce44SJohn Forte * fdata: Error code plus data. 436fcf3ce44SJohn Forte * ha->flash_errlog_ptr: Current Flash error pointer. 437fcf3ce44SJohn Forte * 438fcf3ce44SJohn Forte * Output: 439fcf3ce44SJohn Forte * ha->flash_errlog_ptr: updated pointer. 440fcf3ce44SJohn Forte * 441fcf3ce44SJohn Forte * Returns: 442fcf3ce44SJohn Forte * ql local function return status code. 443fcf3ce44SJohn Forte * 444fcf3ce44SJohn Forte * Context: 445fcf3ce44SJohn Forte * Kernel/Interrupt context. 446fcf3ce44SJohn Forte */ 447fcf3ce44SJohn Forte static int 448fcf3ce44SJohn Forte ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata) 449fcf3ce44SJohn Forte { 4505dfd244aSDaniel Beauregard int rval; 451fcf3ce44SJohn Forte uint64_t time; 452fcf3ce44SJohn Forte uint32_t d1, d2, faddr; 453fcf3ce44SJohn Forte 4545dfd244aSDaniel Beauregard QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 455fcf3ce44SJohn Forte 456fcf3ce44SJohn Forte /* Locate first empty entry */ 457fcf3ce44SJohn Forte for (;;) { 458fcf3ce44SJohn Forte if (ha->flash_errlog_ptr >= 459fcf3ce44SJohn Forte ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 460fcf3ce44SJohn Forte EL(ha, "log full\n"); 461fcf3ce44SJohn Forte return (QL_MEMORY_FULL); 462fcf3ce44SJohn Forte } 463fcf3ce44SJohn Forte 4645dfd244aSDaniel Beauregard faddr = ha->flash_data_addr | ha->flash_errlog_ptr; 465fcf3ce44SJohn Forte ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 466fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr, &d1); 467fcf3ce44SJohn Forte (void) ql_24xx_read_flash(ha, faddr + 1, &d2); 468fcf3ce44SJohn Forte if (d1 == 0xffffffff && d2 == 0xffffffff) { 469fcf3ce44SJohn Forte (void) drv_getparm(TIME, &time); 470fcf3ce44SJohn Forte 471fcf3ce44SJohn Forte /* Enable flash write. */ 4725dfd244aSDaniel Beauregard if ((rval = ql_24xx_unprotect_flash(ha)) != 4735dfd244aSDaniel Beauregard QL_SUCCESS) { 4745dfd244aSDaniel Beauregard EL(ha, "unprotect_flash failed, rval=%xh\n", 4755dfd244aSDaniel Beauregard rval); 4765dfd244aSDaniel Beauregard return (rval); 4775dfd244aSDaniel Beauregard } 478fcf3ce44SJohn Forte 479fcf3ce44SJohn Forte (void) ql_24xx_write_flash(ha, faddr++, LSD(time)); 480fcf3ce44SJohn Forte (void) ql_24xx_write_flash(ha, faddr++, MSD(time)); 481fcf3ce44SJohn Forte (void) ql_24xx_write_flash(ha, faddr++, *fdata++); 482fcf3ce44SJohn Forte (void) ql_24xx_write_flash(ha, faddr++, *fdata); 483fcf3ce44SJohn Forte 484fcf3ce44SJohn Forte /* Enable flash write-protection. */ 485fcf3ce44SJohn Forte ql_24xx_protect_flash(ha); 486fcf3ce44SJohn Forte break; 487fcf3ce44SJohn Forte } 488fcf3ce44SJohn Forte } 489fcf3ce44SJohn Forte 4905dfd244aSDaniel Beauregard QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 491fcf3ce44SJohn Forte 492fcf3ce44SJohn Forte return (QL_SUCCESS); 493fcf3ce44SJohn Forte } 49416dd44c2SDaniel Beauregard 49516dd44c2SDaniel Beauregard /* 49616dd44c2SDaniel Beauregard * ql_dump_el_trace_buffer 49716dd44c2SDaniel Beauregard * Outputs extended logging trace buffer. 49816dd44c2SDaniel Beauregard * 49916dd44c2SDaniel Beauregard * Input: 50016dd44c2SDaniel Beauregard * ha: adapter state pointer. 50116dd44c2SDaniel Beauregard */ 50216dd44c2SDaniel Beauregard void 50316dd44c2SDaniel Beauregard ql_dump_el_trace_buffer(ql_adapter_state_t *ha) 50416dd44c2SDaniel Beauregard { 50516dd44c2SDaniel Beauregard char *dump_start = NULL; 50616dd44c2SDaniel Beauregard char *dump_current = NULL; 50716dd44c2SDaniel Beauregard char *trace_start; 50816dd44c2SDaniel Beauregard char *trace_end; 50916dd44c2SDaniel Beauregard int wrapped = 0; 51016dd44c2SDaniel Beauregard int rval; 51116dd44c2SDaniel Beauregard 51216dd44c2SDaniel Beauregard TRACE_BUFFER_LOCK(ha); 51316dd44c2SDaniel Beauregard 51416dd44c2SDaniel Beauregard rval = ql_validate_trace_desc(ha); 51516dd44c2SDaniel Beauregard if (rval != NULL) { 51616dd44c2SDaniel Beauregard cmn_err(CE_CONT, "%s(%d) Dump EL trace - invalid desc\n", 51716dd44c2SDaniel Beauregard QL_NAME, ha->instance); 51816dd44c2SDaniel Beauregard } else if ((dump_start = ql_find_trace_start(ha)) != NULL) { 51916dd44c2SDaniel Beauregard dump_current = dump_start; 52016dd44c2SDaniel Beauregard trace_start = ha->el_trace_desc->trace_buffer; 52116dd44c2SDaniel Beauregard trace_end = trace_start + 52216dd44c2SDaniel Beauregard ha->el_trace_desc->trace_buffer_size; 52316dd44c2SDaniel Beauregard 52416dd44c2SDaniel Beauregard cmn_err(CE_CONT, "%s(%d) Dump EL trace - start %p %p\n", 52516dd44c2SDaniel Beauregard QL_NAME, ha->instance, 52616dd44c2SDaniel Beauregard (void *)dump_start, (void *)trace_start); 52716dd44c2SDaniel Beauregard 52816dd44c2SDaniel Beauregard while (((uintptr_t)dump_current - (uintptr_t)trace_start) <= 5295dfd244aSDaniel Beauregard (uintptr_t)ha->el_trace_desc->trace_buffer_size) { 53016dd44c2SDaniel Beauregard /* Show it... */ 53116dd44c2SDaniel Beauregard cmn_err(CE_CONT, "%p - %s", (void *)dump_current, 53216dd44c2SDaniel Beauregard dump_current); 53316dd44c2SDaniel Beauregard /* Make the next the current */ 53416dd44c2SDaniel Beauregard dump_current += (strlen(dump_current) + 1); 53516dd44c2SDaniel Beauregard /* check for wrap */ 53616dd44c2SDaniel Beauregard if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) { 53716dd44c2SDaniel Beauregard dump_current = trace_start; 53816dd44c2SDaniel Beauregard wrapped = 1; 53916dd44c2SDaniel Beauregard } else if (wrapped) { 54016dd44c2SDaniel Beauregard /* Don't go past next. */ 54116dd44c2SDaniel Beauregard if ((trace_start + ha->el_trace_desc->next) <= 54216dd44c2SDaniel Beauregard dump_current) { 54316dd44c2SDaniel Beauregard break; 54416dd44c2SDaniel Beauregard } 54516dd44c2SDaniel Beauregard } else if (*dump_current == NULL) { 54616dd44c2SDaniel Beauregard break; 54716dd44c2SDaniel Beauregard } 54816dd44c2SDaniel Beauregard } 54916dd44c2SDaniel Beauregard } 55016dd44c2SDaniel Beauregard TRACE_BUFFER_UNLOCK(ha); 55116dd44c2SDaniel Beauregard } 55216dd44c2SDaniel Beauregard 55316dd44c2SDaniel Beauregard /* 55416dd44c2SDaniel Beauregard * ql_validate_trace_desc 55516dd44c2SDaniel Beauregard * Ensures the extended logging trace descriptor is good 55616dd44c2SDaniel Beauregard * 55716dd44c2SDaniel Beauregard * Input: 55816dd44c2SDaniel Beauregard * ha: adapter state pointer. 55916dd44c2SDaniel Beauregard * 56016dd44c2SDaniel Beauregard * Returns: 56116dd44c2SDaniel Beauregard * ql local function return status code. 56216dd44c2SDaniel Beauregard */ 56316dd44c2SDaniel Beauregard int 56416dd44c2SDaniel Beauregard ql_validate_trace_desc(ql_adapter_state_t *ha) 56516dd44c2SDaniel Beauregard { 56616dd44c2SDaniel Beauregard int rval = DDI_SUCCESS; 56716dd44c2SDaniel Beauregard 56816dd44c2SDaniel Beauregard if (ha->el_trace_desc == NULL) { 56916dd44c2SDaniel Beauregard rval = DDI_FAILURE; 57016dd44c2SDaniel Beauregard } else if (ha->el_trace_desc->trace_buffer == NULL) { 57116dd44c2SDaniel Beauregard rval = DDI_FAILURE; 57216dd44c2SDaniel Beauregard } 57316dd44c2SDaniel Beauregard return (rval); 57416dd44c2SDaniel Beauregard } 57516dd44c2SDaniel Beauregard 57616dd44c2SDaniel Beauregard /* 57716dd44c2SDaniel Beauregard * ql_find_trace_start 57816dd44c2SDaniel Beauregard * Locate the oldest extended logging trace entry. 57916dd44c2SDaniel Beauregard * 58016dd44c2SDaniel Beauregard * Input: 58116dd44c2SDaniel Beauregard * ha: adapter state pointer. 58216dd44c2SDaniel Beauregard * 58316dd44c2SDaniel Beauregard * Returns: 58416dd44c2SDaniel Beauregard * Pointer to a string. 58516dd44c2SDaniel Beauregard * 58616dd44c2SDaniel Beauregard * Context: 58716dd44c2SDaniel Beauregard * Kernel/Interrupt context. 58816dd44c2SDaniel Beauregard */ 58916dd44c2SDaniel Beauregard char * 59016dd44c2SDaniel Beauregard ql_find_trace_start(ql_adapter_state_t *ha) 59116dd44c2SDaniel Beauregard { 59216dd44c2SDaniel Beauregard char *trace_start = 0; 59316dd44c2SDaniel Beauregard char *trace_next = 0; 59416dd44c2SDaniel Beauregard 59516dd44c2SDaniel Beauregard trace_next = ha->el_trace_desc->trace_buffer + ha->el_trace_desc->next; 59616dd44c2SDaniel Beauregard 59716dd44c2SDaniel Beauregard /* 59816dd44c2SDaniel Beauregard * if the buffer has not wrapped next will point at a null so 59916dd44c2SDaniel Beauregard * start is the beginning of the buffer. if next points at a char 60016dd44c2SDaniel Beauregard * then we must traverse the buffer until a null is detected and 60116dd44c2SDaniel Beauregard * that will be the beginning of the oldest whole object in the buffer 60216dd44c2SDaniel Beauregard * which is the start. 60316dd44c2SDaniel Beauregard */ 60416dd44c2SDaniel Beauregard 60516dd44c2SDaniel Beauregard if ((trace_next + EL_BUFFER_RESERVE) >= 60616dd44c2SDaniel Beauregard (ha->el_trace_desc->trace_buffer + 60716dd44c2SDaniel Beauregard ha->el_trace_desc->trace_buffer_size)) { 60816dd44c2SDaniel Beauregard trace_start = ha->el_trace_desc->trace_buffer; 60916dd44c2SDaniel Beauregard } else if (*trace_next != NULL) { 61016dd44c2SDaniel Beauregard trace_start = trace_next + (strlen(trace_next) + 1); 61116dd44c2SDaniel Beauregard } else { 61216dd44c2SDaniel Beauregard trace_start = ha->el_trace_desc->trace_buffer; 61316dd44c2SDaniel Beauregard } 61416dd44c2SDaniel Beauregard return (trace_start); 61516dd44c2SDaniel Beauregard } 616