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