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