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