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