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