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
emlxs_msg_log_create(emlxs_hba_t * hba)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
emlxs_msg_lock_reinit(emlxs_hba_t * hba)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
emlxs_msg_log_destroy(emlxs_hba_t * hba)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
emlxs_msg_log(emlxs_port_t * port,const uint32_t fileno,const uint32_t line,emlxs_msg_t * msg,char * buffer)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
emlxs_msg_log_check(emlxs_port_t * port,emlxs_msg_t * msg)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
emlxs_msg_print_check(emlxs_port_t * port,emlxs_msg_t * msg)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
emlxs_msg_printf(emlxs_port_t * port,const uint32_t fileno,const uint32_t line,emlxs_msg_t * msg,const char * fmt,...)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
emlxs_msg_log_get(emlxs_hba_t * hba,emlxs_log_req_t * req,emlxs_log_resp_t * resp)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
emlxs_msg_sprintf(char * buffer,emlxs_msg_entry_t * entry)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