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