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 2008 QLogic Corporation */ 23 24 /* 25 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma ident "Copyright 2008 QLogic Corporation; ql_debug.c" 30 31 /* 32 * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source 33 * 34 * *********************************************************************** 35 * * ** 36 * * NOTICE ** 37 * * COPYRIGHT (C) 1996-2008 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 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[EL_BUF_LEN]; 149 va_list vl; 150 151 va_start(vl, ce); 152 153 s = va_arg(vl, char *); 154 155 if (ql_enable_ellock) { 156 /* 157 * Used when messages are *maybe* being lost. Adds 158 * a unique number to the message to one can see if 159 * any messages have been dropped. NB: This slows 160 * down the driver, which may make the issue disappear. 161 */ 162 GLOBAL_EL_LOCK(); 163 el_msg_num = ++el_message_number; 164 GLOBAL_EL_UNLOCK(); 165 166 ha == NULL ? 167 (void) snprintf(fmt, EL_BUF_LEN, "QLP%d: %s %s, %s", 168 el_msg_num, QL_NAME, fn, s) : 169 (void) snprintf(fmt, EL_BUF_LEN, QL_BANG "QEL%d %s(%d,%d)" 170 ": %s, %s", el_msg_num, QL_NAME, ha->instance, 171 ha->vp_index, fn, s); 172 } else { 173 ha == NULL ? 174 (void) snprintf(fmt, EL_BUF_LEN, "QLP: %s %s, %s", 175 QL_NAME, fn, s) : 176 (void) snprintf(fmt, EL_BUF_LEN, QL_BANG "QEL %s(%d,%d): " 177 "%s, %s", QL_NAME, ha->instance, ha->vp_index, fn, s); 178 } 179 180 vcmn_err(ce, fmt, vl); 181 182 va_end(vl); 183 } 184 185 /* 186 * ql_stacktrace 187 * Prints out current stack 188 * 189 * Input: 190 * ha: adapter state pointer. 191 * 192 * Context: 193 * Kernel/Interrupt context. 194 */ 195 void 196 ql_stacktrace(ql_adapter_state_t *ha) 197 { 198 int depth, i; 199 pc_t pcstack[DEBUG_STK_DEPTH]; 200 char *sym = NULL; 201 ulong_t off; 202 203 depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH); 204 205 cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 206 ha->vp_index); 207 for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) { 208 sym = kobj_getsymname((uintptr_t)pcstack[i], &off); 209 210 if (sym == NULL) { 211 cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME, 212 ha->instance, ha->vp_index); 213 } else { 214 cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME, 215 ha->instance, ha->vp_index, sym ? sym : "?", off); 216 } 217 } 218 cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance, 219 ha->vp_index); 220 } 221 222 /* 223 * ql_flash_errlog 224 * Adds error to flash error log. 225 * Entry Layout: 226 * uint32_t TimeStamp; 227 * uint16_t CodeData[4]; 228 * 229 * Input: 230 * ha: adapter state pointer. 231 * code: Error code 232 * d1-d3: Error code data 233 * 234 * Returns: 235 * ql local function return status code. 236 * 237 * Context: 238 * Kernel/Interrupt context. 239 */ 240 int 241 ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1, 242 uint16_t d2, uint16_t d3) 243 { 244 char *s; 245 uint32_t marker[2], fdata[2], faddr; 246 int rval; 247 248 QL_PRINT_3(CE_CONT, "(%d): entered\n", ha->instance); 249 250 if (ha->flash_errlog_start == 0) { 251 return (QL_NOT_SUPPORTED); 252 } 253 254 EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3); 255 256 /* 257 * If marker not already found, locate or write marker. 258 */ 259 if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 260 261 /* Create marker. */ 262 marker[0] = CHAR_TO_LONG(ha->fw_subminor_version, 263 ha->fw_minor_version, ha->fw_major_version, 'S'); 264 265 /* 266 * Version should be of the format: YYYYMMDD-v.vv 267 */ 268 if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) { 269 s = &QL_VERSION[9]; 270 } else { 271 s = QL_VERSION; 272 } 273 274 for (marker[1] = 0; *s != '\0'; s++) { 275 if (*s >= '0' && *s <= '9') { 276 marker[1] <<= 4; 277 marker[1] |= *s - '0'; 278 } else if (*s != '.') { 279 break; 280 } 281 } 282 283 /* Locate marker. */ 284 ha->flash_errlog_ptr = ha->flash_errlog_start; 285 for (;;) { 286 faddr = FLASH_DATA_ADDR | ha->flash_errlog_ptr; 287 (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 288 (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 289 if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) { 290 break; 291 } 292 (void) ql_24xx_read_flash(ha, faddr++, &fdata[0]); 293 (void) ql_24xx_read_flash(ha, faddr++, &fdata[1]); 294 ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 295 if (ha->flash_errlog_ptr >= 296 ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 297 EL(ha, "log full\n"); 298 return (QL_MEMORY_FULL); 299 } 300 if (fdata[0] == marker[0] && fdata[1] == marker[1]) { 301 ha->flags |= FLASH_ERRLOG_MARKER; 302 break; 303 } 304 } 305 306 /* No marker, write it. */ 307 if (!(ha->flags & FLASH_ERRLOG_MARKER)) { 308 ha->flags |= FLASH_ERRLOG_MARKER; 309 rval = ql_flash_errlog_store(ha, marker); 310 if (rval != QL_SUCCESS) { 311 EL(ha, "failed marker write=%xh\n", rval); 312 return (rval); 313 } 314 } 315 } 316 317 /* 318 * Store error. 319 */ 320 fdata[0] = SHORT_TO_LONG(d1, code); 321 fdata[1] = SHORT_TO_LONG(d3, d2); 322 rval = ql_flash_errlog_store(ha, fdata); 323 if (rval != QL_SUCCESS) { 324 EL(ha, "failed error write=%xh\n", rval); 325 } else { 326 /*EMPTY*/ 327 QL_PRINT_3(CE_CONT, "(%d): exiting\n", ha->instance); 328 } 329 330 return (rval); 331 } 332 333 /* 334 * ql_flash_errlog_store 335 * Stores error to flash. 336 * Entry Layout: 337 * uint32_t TimeStamp; 338 * uint16_t CodeData[4]; 339 * 340 * Input: 341 * ha: adapter state pointer. 342 * fdata: Error code plus data. 343 * ha->flash_errlog_ptr: Current Flash error pointer. 344 * 345 * Output: 346 * ha->flash_errlog_ptr: updated pointer. 347 * 348 * Returns: 349 * ql local function return status code. 350 * 351 * Context: 352 * Kernel/Interrupt context. 353 */ 354 static int 355 ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata) 356 { 357 uint64_t time; 358 uint32_t d1, d2, faddr; 359 360 QL_PRINT_3(CE_CONT, "(%d): entered\n", ha->instance); 361 362 /* Locate first empty entry */ 363 for (;;) { 364 if (ha->flash_errlog_ptr >= 365 ha->flash_errlog_start + FLASH_ERRLOG_SIZE) { 366 EL(ha, "log full\n"); 367 return (QL_MEMORY_FULL); 368 } 369 370 faddr = FLASH_DATA_ADDR | ha->flash_errlog_ptr; 371 ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE; 372 (void) ql_24xx_read_flash(ha, faddr, &d1); 373 (void) ql_24xx_read_flash(ha, faddr + 1, &d2); 374 if (d1 == 0xffffffff && d2 == 0xffffffff) { 375 (void) drv_getparm(TIME, &time); 376 377 /* Enable flash write. */ 378 ql_24xx_unprotect_flash(ha); 379 380 (void) ql_24xx_write_flash(ha, faddr++, LSD(time)); 381 (void) ql_24xx_write_flash(ha, faddr++, MSD(time)); 382 (void) ql_24xx_write_flash(ha, faddr++, *fdata++); 383 (void) ql_24xx_write_flash(ha, faddr++, *fdata); 384 385 /* Enable flash write-protection. */ 386 ql_24xx_protect_flash(ha); 387 break; 388 } 389 } 390 391 QL_PRINT_3(CE_CONT, "(%d): exiting\n", ha->instance); 392 393 return (QL_SUCCESS); 394 } 395