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 9 * http://www.opensource.org/licenses/cddl1.txt. 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 /* 23 * Copyright (c) 2004-2012 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #define DEF_MSG_STRUCT /* Needed for emlxs_messages.h in emlxs_msg.h */ 28 #include <emlxs.h> 29 30 uint32_t emlxs_log_size = 2048; 31 uint32_t emlxs_log_debugs = 0x7FFFFFFF; 32 uint32_t emlxs_log_notices = 0xFFFFFFFF; 33 uint32_t emlxs_log_warnings = 0xFFFFFFFF; 34 uint32_t emlxs_log_errors = 0xFFFFFFFF; 35 36 static uint32_t emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg); 37 static uint32_t emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg); 38 static void emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry); 39 40 41 uint32_t 42 emlxs_msg_log_create(emlxs_hba_t *hba) 43 { 44 emlxs_msg_log_t *log = &LOG; 45 uint32_t size = sizeof (emlxs_msg_entry_t) * emlxs_log_size; 46 ddi_iblock_cookie_t iblock; 47 48 /* Check if log is already created */ 49 if (log->entry) { 50 cmn_err(CE_WARN, "?%s%d: message log already created. log=%p", 51 DRIVER_NAME, hba->ddiinst, (void *)log); 52 return (0); 53 } 54 55 /* Clear the log */ 56 bzero(log, sizeof (emlxs_msg_log_t)); 57 58 /* Allocate the memory needed for the log file */ 59 log->entry = (emlxs_msg_entry_t *)kmem_zalloc(size, KM_SLEEP); 60 61 /* Initialize */ 62 log->size = emlxs_log_size; 63 log->instance = hba->ddiinst; 64 log->start_time = emlxs_device.log_timestamp; 65 66 if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) { 67 /* Get the current interrupt block cookie */ 68 (void) ddi_get_iblock_cookie(hba->dip, (uint_t)EMLXS_INUMBER, 69 &iblock); 70 71 /* Create the log mutex lock */ 72 mutex_init(&log->lock, NULL, MUTEX_DRIVER, (void *)iblock); 73 } 74 #ifdef MSI_SUPPORT 75 else { 76 /* Create the temporary log mutex lock */ 77 mutex_init(&log->lock, NULL, MUTEX_DRIVER, NULL); 78 } 79 #endif 80 81 return (1); 82 83 } /* emlxs_msg_log_create() */ 84 85 86 void 87 emlxs_msg_lock_reinit(emlxs_hba_t *hba) 88 { 89 emlxs_msg_log_t *log = &LOG; 90 91 /* Check if log is already destroyed */ 92 if (!log->entry) { 93 cmn_err(CE_WARN, 94 "?%s%d: message log already destroyed. log=%p", 95 DRIVER_NAME, hba->ddiinst, (void *)log); 96 97 return; 98 } 99 100 /* Destroy the temporary lock */ 101 mutex_destroy(&log->lock); 102 103 /* Re-create the log mutex lock */ 104 mutex_init(&log->lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(hba->intr_arg)); 105 106 return; 107 108 } /* emlxs_msg_lock_reinit() */ 109 110 void 111 emlxs_msg_log_destroy(emlxs_hba_t *hba) 112 { 113 emlxs_msg_log_t *log = &LOG; 114 uint32_t size; 115 116 /* Check if log is already destroyed */ 117 if (!log->entry) { 118 cmn_err(CE_WARN, 119 "?%s%d: message log already destroyed. log=%p", 120 DRIVER_NAME, hba->ddiinst, (void *)log); 121 122 return; 123 } 124 125 /* Destroy the lock */ 126 mutex_destroy(&log->lock); 127 128 /* Free the log buffer */ 129 size = sizeof (emlxs_msg_entry_t) * log->size; 130 kmem_free(log->entry, size); 131 132 /* Clear the log */ 133 bzero(log, sizeof (emlxs_msg_log_t)); 134 135 return; 136 137 } /* emlxs_msg_log_destroy() */ 138 139 140 uint32_t 141 emlxs_msg_log(emlxs_port_t *port, const uint32_t fileno, const uint32_t line, 142 emlxs_msg_t *msg, char *buffer) 143 { 144 emlxs_hba_t *hba = HBA; 145 emlxs_msg_entry_t *entry; 146 emlxs_msg_entry_t *entry2; 147 clock_t time; 148 emlxs_msg_log_t *log; 149 uint32_t last; 150 emlxs_msg_t *msg2; 151 152 /* Get the log file for this instance */ 153 log = &LOG; 154 155 /* Check if log is initialized */ 156 if (log->entry == NULL) { 157 return (0); 158 } 159 160 mutex_enter(&log->lock); 161 162 /* Get the pointer to the last log entry */ 163 if (log->next == 0) { 164 last = log->size - 1; 165 } else { 166 last = log->next - 1; 167 } 168 entry = &log->entry[last]; 169 170 /* Check if this matches the last message */ 171 if ((entry->instance == log->instance) && 172 (entry->vpi == port->vpi) && 173 (entry->fileno == fileno) && 174 (entry->line == line) && 175 (entry->msg == msg) && 176 (strcmp(entry->buffer, buffer) == 0)) { 177 /* If the same message is being logged then increment */ 178 log->repeat++; 179 180 mutex_exit(&log->lock); 181 182 return (0); 183 } else if (log->repeat) { 184 /* Get the pointer to the next log entry */ 185 entry2 = &log->entry[log->next]; 186 187 /* Increment and check the next entry index */ 188 if (++(log->next) >= log->size) { 189 log->next = 0; 190 } 191 192 switch (entry->msg->level) { 193 case EMLXS_NOTICE: 194 msg2 = &emlxs_notice_msg; 195 break; 196 197 case EMLXS_WARNING: 198 msg2 = &emlxs_warning_msg; 199 break; 200 201 case EMLXS_ERROR: 202 msg2 = &emlxs_error_msg; 203 break; 204 205 case EMLXS_PANIC: 206 msg2 = &emlxs_panic_msg; 207 break; 208 209 case EMLXS_DEBUG: 210 default: 211 msg2 = &emlxs_debug_msg; 212 break; 213 } 214 215 /* Initialize */ 216 entry2->id = log->count++; 217 entry2->fileno = entry->fileno; 218 entry2->line = entry->line; 219 entry2->msg = msg2; 220 entry2->instance = log->instance; 221 entry2->vpi = port->vpi; 222 223 /* Save the additional info buffer */ 224 (void) snprintf(entry2->buffer, MAX_LOG_INFO_LENGTH, 225 "Last message repeated %d time(s).", 226 log->repeat); 227 228 /* Set the entry time stamp */ 229 (void) drv_getparm(LBOLT, &time); 230 entry2->time = time - log->start_time; 231 232 gethrestime(&entry2->id_time); 233 234 log->repeat = 0; 235 } 236 237 /* Get the pointer to the next log entry */ 238 entry = &log->entry[log->next]; 239 240 /* Increment and check the next entry index */ 241 if (++(log->next) >= log->size) { 242 log->next = 0; 243 } 244 245 /* Initialize */ 246 entry->id = log->count++; 247 entry->fileno = fileno; 248 entry->line = line; 249 entry->msg = msg; 250 entry->instance = log->instance; 251 entry->vpi = port->vpi; 252 253 /* Save the additional info buffer */ 254 (void) strncpy(entry->buffer, buffer, (MAX_LOG_INFO_LENGTH - 1)); 255 entry->buffer[MAX_LOG_INFO_LENGTH - 1] = 0; 256 257 /* Set the entry time stamp */ 258 (void) drv_getparm(LBOLT, &time); 259 entry->time = time - log->start_time; 260 261 gethrestime(&entry->id_time); 262 263 mutex_exit(&log->lock); 264 265 return (0); 266 267 } /* emlxs_msg_log() */ 268 269 270 /*ARGSUSED*/ 271 static uint32_t 272 emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg) 273 { 274 275 switch (msg->level) { 276 case EMLXS_DEBUG: 277 if (msg->mask & emlxs_log_debugs) { 278 return (1); 279 } 280 break; 281 282 case EMLXS_NOTICE: 283 if (msg->mask & emlxs_log_notices) { 284 return (1); 285 } 286 break; 287 288 case EMLXS_WARNING: 289 if (msg->mask & emlxs_log_warnings) { 290 return (1); 291 } 292 break; 293 294 case EMLXS_ERROR: 295 if (msg->mask & emlxs_log_errors) { 296 return (1); 297 } 298 break; 299 300 case EMLXS_PANIC: 301 return (1); 302 } 303 304 return (0); 305 306 } /* emlxs_msg_log_check() */ 307 308 309 static uint32_t 310 emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg) 311 { 312 emlxs_hba_t *hba = HBA; 313 emlxs_config_t *cfg; 314 uint32_t rval = 0; 315 316 cfg = &CFG; 317 318 switch (msg->level) { 319 case EMLXS_DEBUG: 320 if (msg->mask & cfg[CFG_CONSOLE_DEBUGS].current) { 321 rval |= 2; 322 } 323 324 if (msg->mask & cfg[CFG_LOG_DEBUGS].current) { 325 rval |= 1; 326 } 327 328 break; 329 330 case EMLXS_NOTICE: 331 if (msg->mask & cfg[CFG_CONSOLE_NOTICES].current) { 332 rval |= 2; 333 } 334 335 if (msg->mask & cfg[CFG_LOG_NOTICES].current) { 336 rval |= 1; 337 } 338 339 break; 340 341 case EMLXS_WARNING: 342 if (msg->mask & cfg[CFG_CONSOLE_WARNINGS].current) { 343 rval |= 2; 344 } 345 346 if (msg->mask & cfg[CFG_LOG_WARNINGS].current) { 347 rval |= 1; 348 } 349 350 break; 351 352 case EMLXS_ERROR: 353 if (msg->mask & cfg[CFG_CONSOLE_ERRORS].current) { 354 rval |= 2; 355 } 356 357 if (msg->mask & cfg[CFG_LOG_ERRORS].current) { 358 rval |= 1; 359 } 360 break; 361 362 case EMLXS_PANIC: 363 default: 364 rval |= 1; 365 366 } 367 368 return (rval); 369 370 } /* emlxs_msg_print_check() */ 371 372 373 void 374 emlxs_msg_printf(emlxs_port_t *port, const uint32_t fileno, 375 const uint32_t line, emlxs_msg_t *msg, 376 const char *fmt, ...) 377 { 378 emlxs_hba_t *hba = HBA; 379 va_list valist; 380 char va_str[256]; 381 char msg_str[512]; 382 char *level; 383 int32_t cmn_level; 384 uint32_t rval; 385 char driver[32]; 386 387 va_str[0] = 0; 388 389 if (fmt) { 390 va_start(valist, fmt); 391 (void) vsnprintf(va_str, sizeof (va_str), fmt, valist); 392 va_end(valist); 393 } 394 395 #ifdef FMA_SUPPORT 396 if (msg->fm_ereport_code) { 397 emlxs_fm_ereport(hba, msg->fm_ereport_code); 398 } 399 400 if (msg->fm_impact_code) { 401 emlxs_fm_service_impact(hba, msg->fm_impact_code); 402 } 403 #endif /* FMA_SUPPORT */ 404 405 /* Check if msg should be logged */ 406 if (emlxs_msg_log_check(port, msg)) { 407 /* Log the message */ 408 if (emlxs_msg_log(port, fileno, line, msg, va_str)) { 409 return; 410 } 411 } 412 413 /* Check if msg should be printed */ 414 if (rval = emlxs_msg_print_check(port, msg)) { 415 cmn_level = CE_CONT; 416 417 switch (msg->level) { 418 case EMLXS_DEBUG: 419 level = " DEBUG"; 420 break; 421 422 case EMLXS_NOTICE: 423 level = " NOTICE"; 424 break; 425 426 case EMLXS_WARNING: 427 level = "WARNING"; 428 break; 429 430 case EMLXS_ERROR: 431 level = " ERROR"; 432 break; 433 434 case EMLXS_PANIC: 435 cmn_level = CE_PANIC; 436 level = " PANIC"; 437 break; 438 439 default: 440 level = "UNKNOWN"; 441 break; 442 } 443 444 if (port->vpi == 0) { 445 (void) snprintf(driver, sizeof (driver), "%s%d", 446 DRIVER_NAME, hba->ddiinst); 447 } else { 448 (void) snprintf(driver, sizeof (driver), "%s%d.%d", 449 DRIVER_NAME, hba->ddiinst, port->vpi); 450 } 451 452 /* Generate the message string */ 453 if (msg->buffer[0] != 0) { 454 if (va_str[0] != 0) { 455 (void) snprintf(msg_str, sizeof (msg_str), 456 "[%2X.%04X]%s:%7s:%4d: %s (%s)\n", fileno, 457 line, driver, level, msg->id, msg->buffer, 458 va_str); 459 } else { 460 (void) snprintf(msg_str, sizeof (msg_str), 461 "[%2X.%04X]%s:%7s:%4d: %s\n", 462 fileno, line, driver, level, msg->id, 463 msg->buffer); 464 } 465 } else { 466 if (va_str[0] != 0) { 467 (void) snprintf(msg_str, sizeof (msg_str), 468 "[%2X.%04X]%s:%7s:%4d: (%s)\n", fileno, 469 line, driver, level, msg->id, va_str); 470 } else { 471 (void) snprintf(msg_str, sizeof (msg_str), 472 "[%2X.%04X]%s:%7s:%4d\n", 473 fileno, line, driver, level, msg->id); 474 } 475 } 476 477 switch (rval) { 478 case 1: /* MESSAGE LOG ONLY */ 479 /* Message log & console, if system booted in */ 480 /* verbose mode (CE_CONT only) */ 481 cmn_err(cmn_level, "?%s", msg_str); 482 break; 483 484 case 2: /* CONSOLE ONLY */ 485 cmn_err(cmn_level, "^%s", msg_str); 486 break; 487 488 case 3: /* CONSOLE AND MESSAGE LOG */ 489 cmn_err(cmn_level, "%s", msg_str); 490 break; 491 492 } 493 494 } 495 496 return; 497 498 } /* emlxs_msg_printf() */ 499 500 501 uint32_t 502 emlxs_msg_log_get(emlxs_hba_t *hba, emlxs_log_req_t *req, 503 emlxs_log_resp_t *resp) 504 { 505 emlxs_msg_log_t *log; 506 uint32_t first; 507 uint32_t last; 508 uint32_t count; 509 uint32_t index; 510 uint32_t i; 511 char *resp_buf; 512 513 log = &LOG; 514 515 mutex_enter(&log->lock); 516 517 /* Check if buffer is empty */ 518 if (log->count == 0) { 519 /* If so, exit now */ 520 resp->first = 0; 521 resp->last = 0; 522 resp->count = 0; 523 mutex_exit(&log->lock); 524 525 return (1); 526 } 527 528 /* Get current log entry ranges */ 529 530 /* Get last entry id saved */ 531 last = log->count - 1; 532 533 /* Check if request is out of current range */ 534 if (req->first > last) { 535 /* if so, exit now */ 536 resp->first = last; 537 resp->last = last; 538 resp->count = 0; 539 mutex_exit(&log->lock); 540 541 return (0); 542 } 543 544 /* Get oldest entry id and its index */ 545 546 /* Check if buffer has already been filled once */ 547 if (log->count >= log->size) { 548 first = log->count - log->size; 549 index = log->next; 550 } else { /* Buffer not yet filled */ 551 552 first = 0; 553 index = 0; 554 } 555 556 /* Check if requested first message is greater than actual. */ 557 /* If so, adjust for it. */ 558 if (req->first > first) { 559 /* Adjust entry index to first requested message */ 560 index += (req->first - first); 561 if (index >= log->size) { 562 index -= log->size; 563 } 564 565 first = req->first; 566 } 567 568 /* Get the total number of messages available for return */ 569 count = last - first + 1; 570 571 /* Check if requested count is less than actual. If so, adjust it. */ 572 if (req->count < count) { 573 count = req->count; 574 } 575 576 /* Fill in the response header */ 577 resp->count = count; 578 resp->first = first; 579 resp->last = last; 580 581 /* Fill the response buffer */ 582 resp_buf = (char *)resp + sizeof (emlxs_log_resp_t); 583 for (i = 0; i < count; i++) { 584 emlxs_msg_sprintf(resp_buf, &log->entry[index]); 585 586 /* Increment the response buffer */ 587 resp_buf += MAX_LOG_MSG_LENGTH; 588 589 /* Increment index */ 590 if (++index >= log->size) { 591 index = 0; 592 } 593 } 594 595 mutex_exit(&log->lock); 596 597 return (1); 598 599 } /* emlxs_msg_log_get() */ 600 601 602 603 static void 604 emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry) 605 { 606 char *level; 607 emlxs_msg_t *msg; 608 uint32_t secs; 609 uint32_t hsecs; 610 char buf[256]; 611 uint32_t buflen; 612 char driver[32]; 613 614 msg = entry->msg; 615 616 hsecs = (entry->time % 100); 617 secs = entry->time / 100; 618 619 switch (msg->level) { 620 case EMLXS_DEBUG: 621 level = " DEBUG"; 622 break; 623 624 case EMLXS_NOTICE: 625 level = " NOTICE"; 626 break; 627 628 case EMLXS_WARNING: 629 level = "WARNING"; 630 break; 631 632 case EMLXS_ERROR: 633 level = " ERROR"; 634 break; 635 636 case EMLXS_PANIC: 637 level = " PANIC"; 638 break; 639 640 default: 641 level = "UNKNOWN"; 642 break; 643 } 644 645 if (entry->vpi == 0) { 646 (void) snprintf(driver, sizeof (driver), "%s%d", DRIVER_NAME, 647 entry->instance); 648 } else { 649 (void) snprintf(driver, sizeof (driver), "%s%d.%d", DRIVER_NAME, 650 entry->instance, entry->vpi); 651 } 652 653 /* Generate the message string */ 654 if (msg->buffer[0] != 0) { 655 if (entry->buffer[0] != 0) { 656 (void) snprintf(buf, sizeof (buf), 657 "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s (%s)\n", 658 secs, hsecs, entry->id, entry->fileno, 659 entry->line, driver, level, msg->id, msg->buffer, 660 entry->buffer); 661 662 } else { 663 (void) snprintf(buf, sizeof (buf), 664 "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s\n", secs, 665 hsecs, entry->id, entry->fileno, entry->line, 666 driver, level, msg->id, msg->buffer); 667 } 668 } else { 669 if (entry->buffer[0] != 0) { 670 (void) snprintf(buf, sizeof (buf), 671 "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: (%s)\n", 672 secs, hsecs, entry->id, entry->fileno, 673 entry->line, driver, level, msg->id, 674 entry->buffer); 675 } else { 676 (void) snprintf(buf, sizeof (buf), 677 "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d\n", 678 secs, hsecs, entry->id, entry->fileno, 679 entry->line, driver, level, msg->id); 680 } 681 } 682 683 bzero(buffer, MAX_LOG_MSG_LENGTH); 684 buflen = strlen(buf); 685 686 if (buflen > (MAX_LOG_MSG_LENGTH - 1)) { 687 (void) strncpy(buffer, buf, (MAX_LOG_MSG_LENGTH - 2)); 688 buffer[MAX_LOG_MSG_LENGTH - 2] = '\n'; 689 } else { 690 (void) strncpy(buffer, buf, buflen); 691 } 692 693 return; 694 695 } /* emlxs_msg_sprintf() */ 696