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 }