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 2008 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 = 1024;
36 /* uint32_t emlxs_log_debugs   = 0x000FFFFF; */
37 uint32_t emlxs_log_debugs = 0x7FFFFFFF;
38 uint32_t emlxs_log_notices = 0xFFFFFFFF;
39 uint32_t emlxs_log_warnings = 0xFFFFFFFF;
40 uint32_t emlxs_log_errors = 0xFFFFFFFF;
41 
42 static uint32_t emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg);
43 static uint32_t emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg);
44 static void emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry);
45 
46 
47 uint32_t
48 emlxs_msg_log_create(emlxs_hba_t *hba)
49 {
50 	emlxs_msg_log_t *log = &LOG;
51 	uint32_t size = sizeof (emlxs_msg_entry_t) * emlxs_log_size;
52 	char buf[40];
53 #ifdef MSI_SUPPORT
54 	ddi_intr_handle_t handle;
55 	uint32_t intr_pri;
56 	int32_t actual;
57 	uint32_t ret;
58 #endif	/* MSI_SUPPORT */
59 	ddi_iblock_cookie_t iblock;
60 
61 	/* Check if log is already created */
62 	if (log->entry) {
63 		cmn_err(CE_WARN, "?%s%d: message log already created. log=%p",
64 		    DRIVER_NAME, hba->ddiinst, (void *) log);
65 		return (0);
66 	}
67 	/* Clear the log */
68 	bzero(log, sizeof (emlxs_msg_log_t));
69 
70 	/* Allocate the memory needed for the log file */
71 	if (!(log->entry = (emlxs_msg_entry_t *)kmem_zalloc(size, KM_SLEEP))) {
72 		cmn_err(CE_WARN, "?%s%d: Unable to allocate log memory. log=%p",
73 		    DRIVER_NAME, hba->ddiinst, (void *) log);
74 		return (0);
75 	}
76 	/* Initialize */
77 	log->size = emlxs_log_size;
78 	log->instance = hba->ddiinst;
79 	log->start_time = emlxs_device.log_timestamp;
80 
81 	(void) sprintf(buf, "?%s%d_log_lock control variable", DRIVER_NAME,
82 	    hba->ddiinst);
83 	cv_init(&log->lock_cv, buf, CV_DRIVER, NULL);
84 
85 	(void) sprintf(buf, "?%s%d_log_lock mutex", DRIVER_NAME, hba->ddiinst);
86 
87 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
88 		/* Get the current interrupt block cookie */
89 		(void) ddi_get_iblock_cookie(hba->dip, (uint_t)EMLXS_INUMBER,
90 		    &iblock);
91 
92 		/* Create the log mutex lock */
93 		mutex_init(&log->lock, buf, MUTEX_DRIVER, (void *) iblock);
94 	}
95 #ifdef  MSI_SUPPORT
96 	else {
97 
98 		/* Allocate a temporary interrupt handle */
99 		actual = 0;
100 		ret = ddi_intr_alloc(hba->dip, &handle, DDI_INTR_TYPE_FIXED,
101 		    EMLXS_MSI_INUMBER, 1, &actual, DDI_INTR_ALLOC_NORMAL);
102 
103 		if (ret != DDI_SUCCESS || actual == 0) {
104 			cmn_err(CE_WARN, "?%s%d: Unable to allocate "
105 			    "temporary interrupt handle. ret=%d actual=%d",
106 			    DRIVER_NAME, hba->ddiinst, ret, actual);
107 
108 			/* Free the log buffer */
109 			kmem_free(log->entry, size);
110 			bzero(log, sizeof (emlxs_msg_log_t));
111 
112 			return (0);
113 		}
114 		/* Get the current interrupt priority */
115 		ret = ddi_intr_get_pri(handle, &intr_pri);
116 
117 		if (ret != DDI_SUCCESS) {
118 			cmn_err(CE_WARN, "?%s%d: Unable to get interrupt "
119 			    "priority. ret=%d", DRIVER_NAME, hba->ddiinst, ret);
120 
121 			/* Free the log buffer */
122 			kmem_free(log->entry, size);
123 			bzero(log, sizeof (emlxs_msg_log_t));
124 
125 			return (0);
126 		}
127 		/* Create the log mutex lock */
128 		mutex_init(&log->lock, buf, MUTEX_DRIVER,
129 		    (void *)(unsigned long) intr_pri);
130 
131 		/* Free the temporary handle */
132 		(void) ddi_intr_free(handle);
133 	}
134 #endif
135 
136 	return (1);
137 
138 } /* emlxs_msg_log_create() */
139 
140 
141 uint32_t
142 emlxs_msg_log_destroy(emlxs_hba_t *hba)
143 {
144 	emlxs_msg_log_t *log = &LOG;
145 	uint32_t size;
146 	emlxs_msg_entry_t *entry;
147 	uint32_t i;
148 
149 	/* Check if log is already destroyed */
150 	if (!log->entry) {
151 		cmn_err(CE_WARN, "?%s%d: message log already destroyed. log=%p",
152 		    DRIVER_NAME, hba->ddiinst, (void *) log);
153 
154 		return (1);
155 	}
156 	/*
157 	 * If events are being logged there might be threads waiting so
158 	 * release them
159 	 */
160 	if (hba->log_events) {
161 		mutex_enter(&log->lock);
162 		hba->log_events = 0;
163 		cv_broadcast(&log->lock_cv);
164 		mutex_exit(&log->lock);
165 
166 		DELAYMS(1);
167 	}
168 	/* Destroy the lock */
169 	mutex_destroy(&log->lock);
170 	cv_destroy(&log->lock_cv);
171 
172 	/* Free the context buffers */
173 	for (i = 0; i < log->size; i++) {
174 		entry = &log->entry[i];
175 
176 		if (entry->bp && entry->size) {
177 			kmem_free(entry->bp, entry->size);
178 		}
179 	}
180 
181 	/* Free the log buffer */
182 	size = sizeof (emlxs_msg_entry_t) * log->size;
183 	kmem_free(log->entry, size);
184 
185 	/* Clear the log */
186 	bzero(log, sizeof (emlxs_msg_log_t));
187 
188 	return (1);
189 
190 } /* emlxs_msg_log_destroy() */
191 
192 
193 
194 uint32_t
195 emlxs_msg_log(emlxs_port_t *port, const uint32_t fileno, const uint32_t line,
196     void *bp, uint32_t size, emlxs_msg_t *msg, char *buffer)
197 {
198 	emlxs_hba_t *hba = HBA;
199 	emlxs_msg_entry_t *entry;
200 	emlxs_msg_entry_t *entry2;
201 	clock_t time;
202 	emlxs_msg_log_t *log;
203 	uint32_t last;
204 	uint32_t mask;
205 	emlxs_msg_t *msg2;
206 	uint32_t rxid;
207 	uint32_t i;
208 
209 	/* Get the log file for this instance */
210 	log = &LOG;
211 
212 	/* Check if log is initialized */
213 	if (log->entry == NULL) {
214 
215 		if (port->vpi == 0) {
216 			cmn_err(CE_WARN, "?%s%d: message log not created. "
217 			    "log=%p", DRIVER_NAME, hba->ddiinst, (void *) log);
218 		} else {
219 			cmn_err(CE_WARN, "?%s%d.%d: message log not created. "
220 			    "log=%p", DRIVER_NAME, hba->ddiinst, port->vpi,
221 			    (void *) log);
222 		}
223 
224 		if (bp && size) {
225 			kmem_free(bp, size);
226 		}
227 		return (1);
228 	}
229 	mutex_enter(&log->lock);
230 
231 	/* Get the pointer to the last log entry */
232 	if (log->next == 0) {
233 		last = log->size - 1;
234 	} else {
235 		last = log->next - 1;
236 	}
237 	entry = &log->entry[last];
238 
239 	/* Check if this matches the last message */
240 	if ((entry->instance == log->instance) &&
241 	    (entry->vpi == port->vpi) &&
242 	    (entry->fileno == fileno) &&
243 	    (entry->line == line) &&
244 	    (entry->bp == bp) &&
245 	    (entry->size == size) &&
246 	    (entry->msg == msg) &&
247 	    (strcmp(entry->buffer, buffer) == 0)) {
248 		/* If the same message is being logged then increment */
249 		log->repeat++;
250 
251 		mutex_exit(&log->lock);
252 
253 		return (0);
254 	} else if (log->repeat) {
255 		/* Get the pointer to the next log entry */
256 		entry2 = &log->entry[log->next];
257 
258 		/* Increment and check the next entry index */
259 		if (++(log->next) >= log->size) {
260 			log->next = 0;
261 		}
262 		switch (entry->msg->level) {
263 		case EMLXS_DEBUG:
264 			msg2 = &emlxs_debug_msg;
265 			break;
266 
267 		case EMLXS_NOTICE:
268 			msg2 = &emlxs_notice_msg;
269 			break;
270 
271 		case EMLXS_WARNING:
272 			msg2 = &emlxs_warning_msg;
273 			break;
274 
275 		case EMLXS_ERROR:
276 			msg2 = &emlxs_error_msg;
277 			break;
278 
279 		case EMLXS_PANIC:
280 			msg2 = &emlxs_panic_msg;
281 			break;
282 
283 		case EMLXS_EVENT:
284 			msg2 = &emlxs_event_msg;
285 			break;
286 		}
287 
288 		/* Check if we are about to overwrite an event entry */
289 		if (entry2->msg && (entry2->msg->level == EMLXS_EVENT)) {
290 			/* Check if this event has not been acquired */
291 			if (log->count > (hba->hba_event.last_id + log->size)) {
292 				hba->hba_event.missed++;
293 
294 				if (entry2->msg->mask == EVT_CT) {
295 					/* Abort exchange */
296 					rxid = *((uint32_t *)entry2->bp);
297 					emlxs_abort_ct_exchange(port, rxid);
298 				}
299 			}
300 		}
301 		/* Free the old context buffer since we are about to erase it */
302 		if (entry2->bp && entry2->size) {
303 			kmem_free(entry2->bp, entry2->size);
304 		}
305 		/* Initialize */
306 		entry2->id = log->count++;
307 		entry2->fileno = entry->fileno;
308 		entry2->line = entry->line;
309 		entry2->bp = 0;
310 		entry2->size = 0;
311 		entry2->msg = msg2;
312 		entry2->instance = log->instance;
313 		entry2->vpi = port->vpi;
314 
315 		/* Save the additional info buffer */
316 		(void) sprintf(entry2->buffer,
317 		    "Last message repeated %d time(s).",
318 		    log->repeat);
319 
320 		/* Set the entry time stamp */
321 		(void) drv_getparm(LBOLT, &time);
322 		entry2->time = time - log->start_time;
323 
324 		log->repeat = 0;
325 	}
326 	/* Get the pointer to the next log entry */
327 	entry = &log->entry[log->next];
328 
329 	/* Increment and check the next entry index */
330 	if (++(log->next) >= log->size) {
331 		log->next = 0;
332 	}
333 	/* Check if we are about to overwrite an event entry */
334 	if (entry->msg && (entry->msg->level == EMLXS_EVENT)) {
335 		/* Check if this event has not been acquired */
336 		if (log->count > (hba->hba_event.last_id + log->size)) {
337 			hba->hba_event.missed++;
338 
339 			if (entry->msg->mask == EVT_CT) {
340 				/* Abort exchange */
341 				rxid = *((uint32_t *)entry->bp);
342 				emlxs_abort_ct_exchange(port, rxid);
343 			}
344 		}
345 	}
346 	/* Free the old context buffer since we are about to erase it */
347 	if (entry->bp && entry->size) {
348 		kmem_free(entry->bp, entry->size);
349 	}
350 	/* Initialize */
351 	entry->id = log->count++;
352 	entry->fileno = fileno;
353 	entry->line = line;
354 	entry->bp = bp;
355 	entry->size = size;
356 	entry->msg = msg;
357 	entry->instance = log->instance;
358 	entry->vpi = port->vpi;
359 
360 	/* Save the additional info buffer */
361 	(void) strncpy(entry->buffer, buffer, (MAX_LOG_INFO_LENGTH - 1));
362 	entry->buffer[MAX_LOG_INFO_LENGTH - 1] = 0;
363 
364 	/* Set the entry time stamp */
365 	(void) drv_getparm(LBOLT, &time);
366 	entry->time = time - log->start_time;
367 
368 	/* Check for a new event */
369 	if (msg->level == EMLXS_EVENT) {
370 		/* Update the event id */
371 		mask = msg->mask;
372 		for (i = 0; i < 32; i++) {
373 			if (mask & 0x01) {
374 				hba->hba_event.new++;
375 				log->event_id[i] = entry->id;
376 				cv_broadcast(&log->lock_cv);
377 				break;
378 			}
379 			mask >>= 1;
380 		}
381 	}
382 	mutex_exit(&log->lock);
383 
384 	return (0);
385 
386 } /* emlxs_msg_log() */
387 
388 
389 static uint32_t
390 emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg)
391 {
392 	emlxs_hba_t *hba = HBA;
393 
394 	switch (msg->level) {
395 	case EMLXS_DEBUG:
396 		if (msg->mask & emlxs_log_debugs) {
397 			return (1);
398 		}
399 		break;
400 
401 	case EMLXS_NOTICE:
402 		if (msg->mask & emlxs_log_notices) {
403 			return (1);
404 		}
405 		break;
406 
407 	case EMLXS_WARNING:
408 		if (msg->mask & emlxs_log_warnings) {
409 			return (1);
410 		}
411 		break;
412 
413 	case EMLXS_ERROR:
414 		if (msg->mask & emlxs_log_errors) {
415 			return (1);
416 		}
417 		break;
418 
419 	case EMLXS_EVENT:
420 		if (msg->mask & hba->log_events) {
421 			return (1);
422 		}
423 		break;
424 
425 	case EMLXS_PANIC:
426 		return (1);
427 	}
428 
429 	return (0);
430 
431 } /* emlxs_msg_log_check() */
432 
433 
434 static uint32_t
435 emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg)
436 {
437 	emlxs_hba_t *hba = HBA;
438 	emlxs_config_t *cfg;
439 	uint32_t rval = 0;
440 
441 	cfg = &CFG;
442 
443 	switch (msg->level) {
444 	case EMLXS_DEBUG:
445 		if (msg->mask & cfg[CFG_CONSOLE_DEBUGS].current) {
446 			rval |= 2;
447 		}
448 		if (msg->mask & cfg[CFG_LOG_DEBUGS].current) {
449 			rval |= 1;
450 		}
451 		break;
452 
453 	case EMLXS_NOTICE:
454 		if (msg->mask & cfg[CFG_CONSOLE_NOTICES].current) {
455 			rval |= 2;
456 		}
457 		if (msg->mask & cfg[CFG_LOG_NOTICES].current) {
458 			rval |= 1;
459 		}
460 		break;
461 
462 	case EMLXS_WARNING:
463 		if (msg->mask & cfg[CFG_CONSOLE_WARNINGS].current) {
464 			rval |= 2;
465 		}
466 		if (msg->mask & cfg[CFG_LOG_WARNINGS].current) {
467 			rval |= 1;
468 		}
469 		break;
470 
471 	case EMLXS_ERROR:
472 		if (msg->mask & cfg[CFG_CONSOLE_ERRORS].current) {
473 			rval |= 2;
474 		}
475 		if (msg->mask & cfg[CFG_LOG_ERRORS].current) {
476 			rval |= 1;
477 		}
478 		break;
479 
480 	case EMLXS_EVENT:
481 		/* Only print an event if it is being logged internally */
482 		if (msg->mask & hba->log_events) {
483 			if (msg->mask & cfg[CFG_CONSOLE_EVENTS].current) {
484 				rval |= 2;
485 			}
486 			if (msg->mask & cfg[CFG_LOG_EVENTS].current) {
487 				rval |= 1;
488 			}
489 		}
490 		break;
491 
492 	case EMLXS_PANIC:
493 	default:
494 		rval |= 1;
495 
496 	}
497 
498 	return (rval);
499 
500 } /* emlxs_msg_print_check() */
501 
502 
503 void
504 emlxs_msg_printf(emlxs_port_t *port, const uint32_t fileno, const uint32_t line,
505     void *bp, uint32_t size, emlxs_msg_t *msg, const char *fmt, ...)
506 {
507 	emlxs_hba_t *hba = HBA;
508 	va_list valist;
509 	char va_str[256];
510 	char msg_str[512];
511 	char *level;
512 	int32_t cmn_level;
513 	uint32_t rval;
514 	uint32_t logged;
515 	char driver[32];
516 
517 	va_str[0] = 0;
518 
519 	if (fmt) {
520 		va_start(valist, fmt);
521 		(void) vsprintf(va_str, fmt, valist);
522 		va_end(valist);
523 	}
524 	/* Check if msg should be logged */
525 	if ((logged = emlxs_msg_log_check(port, msg))) {
526 		/* Log the message */
527 		if (emlxs_msg_log(port, fileno, line, bp, size, msg, va_str)) {
528 			return;
529 		}
530 	}
531 	/* Check if msg should be printed */
532 	if (rval = emlxs_msg_print_check(port, msg)) {
533 		cmn_level = CE_CONT;
534 
535 		switch (msg->level) {
536 		case EMLXS_DEBUG:
537 			level = "  DEBUG";
538 			break;
539 
540 		case EMLXS_NOTICE:
541 			level = " NOTICE";
542 			break;
543 
544 		case EMLXS_WARNING:
545 			level = "WARNING";
546 			break;
547 
548 		case EMLXS_ERROR:
549 			level = "  ERROR";
550 			break;
551 
552 		case EMLXS_PANIC:
553 			cmn_level = CE_PANIC;
554 			level = "  PANIC";
555 			break;
556 
557 		case EMLXS_EVENT:
558 			level = "  EVENT";
559 			break;
560 
561 		default:
562 			level = "UNKNOWN";
563 			break;
564 		}
565 
566 		if (port->vpi == 0) {
567 			(void) sprintf(driver, "%s%d", DRIVER_NAME,
568 			    hba->ddiinst);
569 		} else {
570 			(void) sprintf(driver, "%s%d.%d", DRIVER_NAME,
571 			    hba->ddiinst, port->vpi);
572 		}
573 
574 		/* Generate the message string */
575 		if (msg->buffer[0] != 0) {
576 			if (va_str[0] != 0) {
577 				(void) sprintf(msg_str,
578 				    "[%2X.%04X]%s:%7s:%4d: %s (%s)\n",
579 				    fileno, line, driver, level, msg->id,
580 				    msg->buffer, va_str);
581 			} else {
582 				(void) sprintf(msg_str,
583 				    "[%2X.%04X]%s:%7s:%4d: %s\n",
584 				    fileno, line, driver, level, msg->id,
585 				    msg->buffer);
586 			}
587 		} else {
588 			if (va_str[0] != 0) {
589 				(void) sprintf(msg_str,
590 				    "[%2X.%04X]%s:%7s:%4d: (%s)\n",
591 				    fileno, line, driver, level, msg->id,
592 				    va_str);
593 			} else {
594 				(void) sprintf(msg_str,
595 				    "[%2X.%04X]%s:%7s:%4d\n",
596 				    fileno, line, driver, level, msg->id);
597 			}
598 		}
599 
600 		switch (rval) {
601 		case 1:	/* MESSAGE LOG ONLY */
602 			/* cmn_err(cmn_level, "!%s", msg_str); */
603 			/*
604 			 * Message log & console, if system booted in verbose
605 			 *   mode (CE_CONT only)
606 			 */
607 			cmn_err(cmn_level, "?%s", msg_str);
608 			break;
609 
610 		case 2:	/* CONSOLE ONLY */
611 			cmn_err(cmn_level, "^%s", msg_str);
612 			break;
613 
614 		case 3:	/* CONSOLE AND MESSAGE LOG */
615 			cmn_err(cmn_level, "%s", msg_str);
616 			break;
617 
618 		}
619 
620 	}
621 	/* If message was not logged, then free any context buffer provided */
622 	if (!logged && bp && size) {
623 		kmem_free(bp, size);
624 	}
625 	return;
626 
627 } /* emlxs_msg_printf() */
628 
629 
630 uint32_t
631 emlxs_msg_log_get(emlxs_hba_t *hba, emlxs_log_req_t *req,
632     emlxs_log_resp_t *resp)
633 {
634 	emlxs_msg_log_t *log;
635 	uint32_t first;
636 	uint32_t last;
637 	uint32_t count;
638 	uint32_t index;
639 	uint32_t i;
640 	char *resp_buf;
641 
642 	log = &LOG;
643 
644 	mutex_enter(&log->lock);
645 
646 	/* Check if buffer is empty */
647 	if (log->count == 0) {
648 		/* If so, exit now */
649 		resp->first = 0;
650 		resp->last = 0;
651 		resp->count = 0;
652 		mutex_exit(&log->lock);
653 
654 		return (1);
655 	}
656 	/* Get current log entry ranges */
657 
658 	/* Get last entry id saved */
659 	last = log->count - 1;
660 
661 	/* Check if request is out of current range */
662 	if (req->first > last) {
663 		/* if so, exit now */
664 		resp->first = last;
665 		resp->last = last;
666 		resp->count = 0;
667 		mutex_exit(&log->lock);
668 
669 		return (0);
670 	}
671 	/* Get oldest entry id and its index */
672 
673 	/* Check if buffer has already been filled once */
674 	if (log->count >= log->size) {
675 		first = log->count - log->size;
676 		index = log->next;
677 	} else {	/* Buffer not yet filled */
678 		first = 0;
679 		index = 0;
680 	}
681 
682 	/*
683 	 * Check if requested first message is greater than actual. If so,
684 	 * adjust for it.
685 	 */
686 	if (req->first > first) {
687 		/* Adjust entry index to first requested message */
688 		index += (req->first - first);
689 		if (index >= log->size) {
690 			index -= log->size;
691 		}
692 		first = req->first;
693 	}
694 	/* Get the total number of messages available for return */
695 	count = last - first + 1;
696 
697 	/* Check if requested count is less than actual.  If so, adjust it. */
698 	if (req->count < count) {
699 		count = req->count;
700 	}
701 	/* Fill in the response header */
702 	resp->count = count;
703 	resp->first = first;
704 	resp->last = last;
705 
706 	/* Fill the response buffer */
707 	resp_buf = (char *)resp + sizeof (emlxs_log_resp_t);
708 	for (i = 0; i < count; i++) {
709 		emlxs_msg_sprintf(resp_buf, &log->entry[index]);
710 
711 		/* Increment the response buffer */
712 		resp_buf += MAX_LOG_MSG_LENGTH;
713 
714 		/* Increment index */
715 		if (++index >= log->size) {
716 			index = 0;
717 		}
718 	}
719 
720 	mutex_exit(&log->lock);
721 
722 	return (1);
723 
724 } /* emlxs_msg_log_get() */
725 
726 
727 
728 static void
729 emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry)
730 {
731 	char *level;
732 	emlxs_msg_t *msg;
733 	uint32_t secs;
734 	uint32_t hsecs;
735 	char buf[256];
736 	uint32_t buflen;
737 	char driver[32];
738 
739 	msg = entry->msg;
740 	hsecs = (entry->time % 100);
741 	secs = entry->time / 100;
742 
743 	switch (msg->level) {
744 	case EMLXS_DEBUG:
745 		level = "  DEBUG";
746 		break;
747 
748 	case EMLXS_NOTICE:
749 		level = " NOTICE";
750 		break;
751 
752 	case EMLXS_WARNING:
753 		level = "WARNING";
754 		break;
755 
756 	case EMLXS_ERROR:
757 		level = "  ERROR";
758 		break;
759 
760 	case EMLXS_PANIC:
761 		level = "  PANIC";
762 		break;
763 
764 	case EMLXS_EVENT:
765 		level = "  EVENT";
766 		break;
767 
768 	default:
769 		level = "UNKNOWN";
770 		break;
771 	}
772 
773 	if (entry->vpi == 0) {
774 		(void) sprintf(driver, "%s%d", DRIVER_NAME, entry->instance);
775 	} else {
776 		(void) sprintf(driver, "%s%d.%d", DRIVER_NAME, entry->instance,
777 		    entry->vpi);
778 	}
779 
780 	/* Generate the message string */
781 	if (msg->buffer[0] != 0) {
782 		if (entry->buffer[0] != 0) {
783 			(void) sprintf(buf,
784 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s (%s)\n",
785 			    secs, hsecs, entry->id, entry->fileno, entry->line,
786 			    driver, level, msg->id, msg->buffer, entry->buffer);
787 
788 		} else {
789 			(void) sprintf(buf,
790 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s\n",
791 			    secs, hsecs, entry->id, entry->fileno, entry->line,
792 			    driver, level, msg->id, msg->buffer);
793 		}
794 	} else {
795 		if (entry->buffer[0] != 0) {
796 			(void) sprintf(buf,
797 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: (%s)\n",
798 			    secs, hsecs, entry->id, entry->fileno, entry->line,
799 			    driver, level, msg->id, entry->buffer);
800 		} else {
801 			(void) sprintf(buf,
802 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d\n",
803 			    secs, hsecs, entry->id, entry->fileno, entry->line,
804 			    driver, level, msg->id);
805 		}
806 	}
807 
808 	bzero(buffer, MAX_LOG_MSG_LENGTH);
809 	buflen = strlen(buf);
810 
811 	if (buflen > (MAX_LOG_MSG_LENGTH - 1)) {
812 		(void) strncpy(buffer, buf, (MAX_LOG_MSG_LENGTH - 2));
813 		buffer[MAX_LOG_MSG_LENGTH - 2] = '\n';
814 	} else {
815 		(void) strncpy(buffer, buf, buflen);
816 	}
817 
818 	return;
819 
820 } /* emlxs_msg_sprintf() */
821 
822 
823 
824 
825 void
826 emlxs_log_rscn_event(emlxs_port_t *port, uint8_t *payload, uint32_t size)
827 {
828 #ifdef DFC_SUPPORT
829 	uint8_t *bp;
830 	uint32_t *ptr;
831 
832 	/* Check if the event is being requested */
833 	/*
834 	 * if(!(hba->log_events & EVT_RSCN)) { return; }
835 	 */
836 
837 	if (size > MAX_RSCN_PAYLOAD) {
838 		size = MAX_RSCN_PAYLOAD;
839 	}
840 	size += sizeof (uint32_t);
841 
842 	/* Save a copy of the payload for the event log */
843 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
844 		return;
845 	}
846 	/*
847 	 * Buffer Format: word[0] = DID of the RSCN word[1] = RSCN Payload
848 	 */
849 	ptr = (uint32_t *)bp;
850 	*ptr++ = port->did;
851 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
852 
853 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_rscn_event,
854 	    "bp=%p size=%d", bp, size);
855 
856 #endif	/* DFC_SUPPORT */
857 	return;
858 
859 } /* emlxs_log_rscn_event() */
860 
861 
862 uint32_t
863 emlxs_log_ct_event(emlxs_port_t *port, uint8_t *payload, uint32_t size,
864     uint32_t rxid)
865 {
866 #ifdef DFC_SUPPORT
867 	emlxs_hba_t *hba = HBA;
868 	uint8_t *bp;
869 	uint32_t *ptr;
870 
871 	/* Check if the event is being requested */
872 	if (!(hba->log_events & EVT_CT)) {
873 		return (1);
874 	}
875 	if (size > MAX_CT_PAYLOAD) {
876 		size = MAX_CT_PAYLOAD;
877 	}
878 	size += sizeof (uint32_t);
879 
880 	/* Save a copy of the payload for the event log */
881 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
882 		return (1);
883 	}
884 	/*
885 	 * Buffer Format: word[0] = RXID tag for outgoing reply to this CT
886 	 * request word[1] = CT Payload
887 	 */
888 	ptr = (uint32_t *)bp;
889 	*ptr++ = rxid;
890 
891 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
892 
893 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_ct_event,
894 	    "bp=%p size=%d rxid=%x", bp, size, rxid);
895 
896 	return (0);
897 
898 #else
899 	return (1);
900 
901 #endif	/* DFC_SUPPORT */
902 
903 
904 } /* emlxs_log_ct_event() */
905 
906 
907 void
908 emlxs_log_link_event(emlxs_port_t *port)
909 {
910 #ifdef DFC_SUPPORT
911 	emlxs_hba_t *hba = HBA;
912 	uint8_t *bp;
913 	dfc_linkinfo_t *linkinfo;
914 	uint8_t *byte;
915 	uint8_t *linkspeed;
916 	uint8_t *liptype;
917 	uint8_t *resv1;
918 	uint8_t *resv2;
919 	uint32_t size;
920 
921 	/* Check if the event is being requested */
922 	/*
923 	 * if(!(hba->log_events & EVT_LINK)) { return; }
924 	 */
925 	size = sizeof (dfc_linkinfo_t) + sizeof (uint32_t);
926 
927 	/* Save a copy of the buffer for the event log */
928 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
929 		return;
930 	}
931 	/*
932 	 * Buffer Format: word[0] = Linkspeed:8 word[0] = LIP_type:8 word[0]
933 	 * = resv1:8 word[0] = resv2:8 word[1] = dfc_linkinfo_t data
934 	 */
935 	byte = (uint8_t *)bp;
936 	linkspeed = &byte[0];
937 	liptype = &byte[1];
938 	resv1 = &byte[2];
939 	resv2 = &byte[3];
940 	linkinfo = (dfc_linkinfo_t *)& byte[4];
941 
942 	*resv1 = 0;
943 	*resv2 = 0;
944 
945 	if (hba->state <= FC_LINK_DOWN) {
946 		*linkspeed = 0;
947 		*liptype = 0;
948 	} else {
949 		/* Set linkspeed */
950 		if (hba->linkspeed == LA_2GHZ_LINK) {
951 			*linkspeed = HBA_PORTSPEED_2GBIT;
952 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
953 			*linkspeed = HBA_PORTSPEED_4GBIT;
954 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
955 			*linkspeed = HBA_PORTSPEED_8GBIT;
956 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
957 			*linkspeed = HBA_PORTSPEED_10GBIT;
958 		} else {
959 			*linkspeed = HBA_PORTSPEED_1GBIT;
960 		}
961 
962 		/* Set LIP type */
963 		*liptype = port->lip_type;
964 	}
965 
966 	bzero(linkinfo, sizeof (dfc_linkinfo_t));
967 
968 	linkinfo->a_linkEventTag = hba->link_event_tag;
969 	linkinfo->a_linkUp = HBASTATS.LinkUp;
970 	linkinfo->a_linkDown = HBASTATS.LinkDown;
971 	linkinfo->a_linkMulti = HBASTATS.LinkMultiEvent;
972 
973 	if (hba->state <= FC_LINK_DOWN) {
974 		linkinfo->a_linkState = LNK_DOWN;
975 		linkinfo->a_DID = port->prev_did;
976 	} else if (hba->state < FC_READY) {
977 		linkinfo->a_linkState = LNK_DISCOVERY;
978 	} else {
979 		linkinfo->a_linkState = LNK_READY;
980 	}
981 
982 	if (linkinfo->a_linkState != LNK_DOWN) {
983 		if (hba->topology == TOPOLOGY_LOOP) {
984 			if (hba->flag & FC_FABRIC_ATTACHED) {
985 				linkinfo->a_topology = LNK_PUBLIC_LOOP;
986 			} else {
987 				linkinfo->a_topology = LNK_LOOP;
988 			}
989 
990 			linkinfo->a_alpa = port->did & 0xff;
991 			linkinfo->a_DID = linkinfo->a_alpa;
992 			linkinfo->a_alpaCnt = port->alpa_map[0];
993 
994 			if (linkinfo->a_alpaCnt > 127) {
995 				linkinfo->a_alpaCnt = 127;
996 			}
997 			bcopy((void *) &port->alpa_map[1], linkinfo->a_alpaMap,
998 			    linkinfo->a_alpaCnt);
999 		} else {
1000 			if (port->node_count == 1) {
1001 				linkinfo->a_topology = LNK_PT2PT;
1002 			} else {
1003 				linkinfo->a_topology = LNK_FABRIC;
1004 			}
1005 
1006 			linkinfo->a_DID = port->did;
1007 		}
1008 	}
1009 	bcopy(&hba->wwpn, linkinfo->a_wwpName, 8);
1010 	bcopy(&hba->wwnn, linkinfo->a_wwnName, 8);
1011 
1012 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_link_event,
1013 	    "bp=%p size=%d tag=%x", bp, size, hba->link_event_tag);
1014 
1015 #endif	/* DFC_SUPPORT */
1016 
1017 	return;
1018 
1019 } /* emlxs_log_link_event() */
1020 
1021 
1022 void
1023 emlxs_log_dump_event(emlxs_port_t *port, uint8_t *buffer, uint32_t size)
1024 {
1025 #ifdef DFC_SUPPORT
1026 	emlxs_hba_t *hba = HBA;
1027 	uint8_t *bp;
1028 
1029 	/* Check if the event is being requested */
1030 	if (!(hba->log_events & EVT_DUMP)) {
1031 		return;
1032 	}
1033 	if (buffer && size) {
1034 		/* Save a copy of the buffer for the event log */
1035 		if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1036 			return;
1037 		}
1038 		bcopy(buffer, bp, size);
1039 	} else {
1040 		bp = NULL;
1041 		size = 0;
1042 	}
1043 
1044 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_dump_event,
1045 	    "bp=%p size=%d", bp, size);
1046 
1047 #endif	/* DFC_SUPPORT */
1048 
1049 	return;
1050 
1051 } /* emlxs_log_dump_event() */
1052 
1053 
1054 extern void
1055 emlxs_log_temp_event(emlxs_port_t *port, uint32_t type, uint32_t temp)
1056 {
1057 #ifdef DFC_SUPPORT
1058 	emlxs_hba_t *hba = HBA;
1059 	uint32_t *bp;
1060 	uint32_t size;
1061 
1062 	/* Check if the event is being requested */
1063 	if (!(hba->log_events & EVT_TEMP)) {
1064 		return;
1065 	}
1066 	size = 2 * sizeof (uint32_t);
1067 
1068 	if (!(bp = (uint32_t *)kmem_alloc(size, KM_NOSLEEP))) {
1069 		return;
1070 	}
1071 	bp[0] = type;
1072 	bp[1] = temp;
1073 
1074 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_temp_event,
1075 	    "type=%x temp=%d bp=%p size=%d", type, temp, bp, size);
1076 
1077 #endif	/* DFC_SUPPORT */
1078 
1079 	return;
1080 
1081 } /* emlxs_log_temp_event() */
1082 
1083 
1084 
1085 extern void
1086 emlxs_log_fcoe_event(emlxs_port_t *port, menlo_init_rsp_t *init_rsp)
1087 {
1088 #ifdef DFC_SUPPORT
1089 	emlxs_hba_t *hba = HBA;
1090 	uint8_t *bp;
1091 	uint32_t size;
1092 
1093 	/* Check if the event is being requested */
1094 	if (!(hba->log_events & EVT_FCOE)) {
1095 		return;
1096 	}
1097 	/* Check if this is a FCOE adapter */
1098 	if (hba->model_info.device_id != PCI_DEVICE_ID_LP21000_M) {
1099 		return;
1100 	}
1101 	size = sizeof (menlo_init_rsp_t);
1102 
1103 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1104 		return;
1105 	}
1106 	bcopy((uint8_t *)init_rsp, bp, size);
1107 
1108 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_fcoe_event,
1109 	    "bp=%p size=%d", bp, size);
1110 
1111 #endif	/* DFC_SUPPORT */
1112 
1113 	return;
1114 
1115 } /* emlxs_log_fcoe_event() */
1116 
1117 
1118 
1119 #ifdef DFC_SUPPORT
1120 
1121 extern uint32_t
1122 emlxs_get_dfc_eventinfo(emlxs_port_t *port, HBA_EVENTINFO *eventinfo,
1123     uint32_t *eventcount, uint32_t *missed)
1124 {
1125 	emlxs_hba_t *hba = HBA;
1126 	emlxs_msg_log_t *log;
1127 	uint32_t first;
1128 	uint32_t last;
1129 	uint32_t count;
1130 	uint32_t index;
1131 	emlxs_msg_entry_t *entry;
1132 	dfc_linkinfo_t *linkinfo;
1133 	uint32_t *word;
1134 	uint8_t *byte;
1135 	uint8_t linkspeed;
1136 	uint8_t liptype;
1137 	fc_affected_id_t *aid;
1138 	uint32_t max_events;
1139 	uint32_t events;
1140 	emlxs_hba_event_t *hba_event;
1141 
1142 	if (!eventinfo || !eventcount || !missed) {
1143 		return (DFC_ARG_NULL);
1144 	}
1145 	hba_event = &hba->hba_event;
1146 	max_events = *eventcount;
1147 	*eventcount = 0;
1148 
1149 	log = &LOG;
1150 
1151 	mutex_enter(&log->lock);
1152 
1153 	/* Check if log is empty */
1154 	if (log->count == 0) {
1155 		/* Make sure everything is initialized */
1156 		hba_event->new = 0;
1157 		hba_event->missed = 0;
1158 		hba_event->last_id = 0;
1159 
1160 		mutex_exit(&log->lock);
1161 		return (0);
1162 	}
1163 	/* Safety check */
1164 	if (hba_event->last_id > (log->count - 1)) {
1165 		hba_event->last_id = log->count - 1;
1166 	}
1167 	/* Account for missed events */
1168 	if (hba_event->new > hba_event->missed) {
1169 		hba_event->new -= hba_event->missed;
1170 	} else {
1171 		hba_event->new = 0;
1172 	}
1173 
1174 	*missed = hba_event->missed;
1175 	hba_event->missed = 0;
1176 
1177 	if (!hba_event->new) {
1178 		hba_event->last_id = log->count;
1179 		mutex_exit(&log->lock);
1180 		return (0);
1181 	}
1182 	/* A new event has occurred since last acquisition */
1183 	/* Calculate the current buffer boundaries */
1184 
1185 	/* Get last entry id saved */
1186 	last = log->count - 1;
1187 
1188 	/* Get oldest entry id and its index */
1189 	/* Check if buffer has already been filled once */
1190 	if (log->count >= log->size) {
1191 		first = log->count - log->size;
1192 		index = log->next;
1193 	} else {	/* Buffer not yet filled */
1194 		first = 0;
1195 		index = 0;
1196 	}
1197 
1198 	/*
1199 	 * Check if requested first event is greater than actual. If so,
1200 	 * adjust for it.
1201 	 */
1202 	if (hba_event->last_id > first) {
1203 		/* Adjust entry index to first requested message */
1204 		index += (hba_event->last_id - first);
1205 		if (index >= log->size) {
1206 			index -= log->size;
1207 		}
1208 		first = hba_event->last_id;
1209 	}
1210 	/* Get the total number of new messages */
1211 	count = last - first;
1212 
1213 	/* Scan log for next event */
1214 	events = 0;
1215 	while (count-- && (events < max_events)) {
1216 		if (++index >= log->size) {
1217 			index = 0;
1218 		}
1219 		entry = &log->entry[index];
1220 
1221 		if (!entry->msg) {
1222 			break;
1223 		}
1224 		if ((entry->msg->level == EMLXS_EVENT) &&
1225 		    (entry->msg->mask & (EVT_LINK | EVT_RSCN))) {
1226 			/* Process this event */
1227 			switch (entry->msg->mask) {
1228 			case EVT_LINK:
1229 				byte = (uint8_t *)entry->bp;
1230 				linkspeed = byte[0];
1231 				liptype = byte[1];
1232 				linkinfo = (dfc_linkinfo_t *)& byte[4];
1233 
1234 				if (linkinfo->a_linkState == LNK_DOWN) {
1235 					eventinfo->EventCode =
1236 					    HBA_EVENT_LINK_DOWN;
1237 					eventinfo->Event.Link_EventInfo.
1238 					    PortFcId = linkinfo->a_DID;
1239 					eventinfo->Event.Link_EventInfo.
1240 					    Reserved[0] = 0;
1241 					eventinfo->Event.Link_EventInfo.
1242 					    Reserved[1] = 0;
1243 					eventinfo->Event.Link_EventInfo.
1244 					    Reserved[2] = 0;
1245 				} else {
1246 					eventinfo->EventCode =
1247 					    HBA_EVENT_LINK_UP;
1248 					eventinfo->Event.Link_EventInfo.
1249 					    PortFcId = linkinfo->a_DID;
1250 
1251 					if ((linkinfo->a_topology ==
1252 					    LNK_PUBLIC_LOOP) ||
1253 					    (linkinfo->a_topology ==
1254 					    LNK_LOOP)) {
1255 						eventinfo->Event.Link_EventInfo.
1256 						    Reserved[0] = 2;
1257 					} else {
1258 						eventinfo->Event.Link_EventInfo.
1259 						    Reserved[0] = 1;
1260 					}
1261 
1262 					eventinfo->Event.Link_EventInfo.
1263 					    Reserved[1] = liptype;
1264 					eventinfo->Event.Link_EventInfo.
1265 					    Reserved[2] = linkspeed;
1266 				}
1267 
1268 				break;
1269 
1270 			case EVT_RSCN:
1271 				word = (uint32_t *)entry->bp;
1272 				eventinfo->EventCode = HBA_EVENT_RSCN;
1273 				eventinfo->Event.RSCN_EventInfo.PortFcId =
1274 				    word[0] & 0xFFFFFF;
1275 				/* word[1] is the RSCN payload command */
1276 
1277 				aid = (fc_affected_id_t *)& word[2];
1278 
1279 				switch (aid->aff_format) {
1280 				case 0:	/* Port */
1281 					eventinfo->Event.RSCN_EventInfo.
1282 					    NPortPage =
1283 					    aid->aff_d_id & 0x00ffffff;
1284 					break;
1285 
1286 				case 1:	/* Area */
1287 					eventinfo->Event.RSCN_EventInfo.
1288 					    NPortPage =
1289 					    aid->aff_d_id & 0x00ffff00;
1290 					break;
1291 
1292 				case 2:	/* Domain */
1293 					eventinfo->Event.RSCN_EventInfo.
1294 					    NPortPage =
1295 					    aid->aff_d_id & 0x00ff0000;
1296 					break;
1297 
1298 				case 3:	/* Network */
1299 					eventinfo->Event.RSCN_EventInfo.
1300 					    NPortPage = 0;
1301 					break;
1302 				}
1303 
1304 				eventinfo->Event.RSCN_EventInfo.Reserved[0] = 0;
1305 				eventinfo->Event.RSCN_EventInfo.Reserved[1] = 0;
1306 
1307 				break;
1308 			}
1309 
1310 			eventinfo++;
1311 			events++;
1312 		}
1313 		hba_event->last_id = entry->id;
1314 	}
1315 
1316 	/* Adjust new count */
1317 	if (!count || (events >= hba_event->new)) {
1318 		hba_event->new = 0;
1319 	} else {
1320 		hba_event->new -= events;
1321 	}
1322 
1323 	/* Return number of events acquired */
1324 	*eventcount = events;
1325 
1326 	mutex_exit(&log->lock);
1327 
1328 	return (0);
1329 
1330 } /* emlxs_get_dfc_eventinfo() */
1331 
1332 
1333 uint32_t
1334 emlxs_get_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event,
1335     uint32_t sleep)
1336 {
1337 	emlxs_hba_t *hba = HBA;
1338 	emlxs_msg_log_t *log;
1339 	uint32_t first;
1340 	uint32_t last;
1341 	uint32_t count;
1342 	uint32_t index;
1343 	uint32_t mask;
1344 	uint32_t i;
1345 	emlxs_msg_entry_t *entry;
1346 	uint32_t size;
1347 	uint32_t rc;
1348 
1349 	size = 0;
1350 
1351 	if (dfc_event->dataout && dfc_event->size) {
1352 		size = dfc_event->size;
1353 	}
1354 	dfc_event->size = 0;
1355 
1356 	/* Get the log file pointer */
1357 	log = &LOG;
1358 
1359 	/* Calculate the event index */
1360 	mask = dfc_event->event;
1361 	for (i = 0; i < 32; i++) {
1362 		if (mask & 0x01) {
1363 			break;
1364 		}
1365 		mask >>= 1;
1366 	}
1367 	if (i == 32) {
1368 		return (DFC_ARG_INVALID);
1369 	}
1370 	mutex_enter(&log->lock);
1371 
1372 	/* Check if log is empty */
1373 	if (log->count == 0) {
1374 		/* Make sure everything is initialized */
1375 		log->event_id[i] = 0;
1376 		dfc_event->last_id = 0;
1377 	} else {
1378 		/* Check ranges for safety */
1379 		if (log->event_id[i] > (log->count - 1)) {
1380 			log->event_id[i] = log->count - 1;
1381 		}
1382 		if (dfc_event->last_id > log->event_id[i]) {
1383 			dfc_event->last_id = log->event_id[i];
1384 		}
1385 	}
1386 
1387 wait_for_event:
1388 
1389 	/* Check if no new event has ocurred */
1390 	if (dfc_event->last_id == log->event_id[i]) {
1391 		if (!sleep) {
1392 			mutex_exit(&log->lock);
1393 			return (0);
1394 		}
1395 		/*
1396 		 * While event is still active and no new event has been
1397 		 * logged
1398 		 */
1399 		while ((dfc_event->event & hba->log_events) &&
1400 		    (dfc_event->last_id == log->event_id[i])) {
1401 			rc = cv_wait_sig(&log->lock_cv, &log->lock);
1402 
1403 			/* Check if thread was killed by kernel */
1404 			if (rc == 0) {
1405 				dfc_event->pid = 0;
1406 				dfc_event->event = 0;
1407 				mutex_exit(&log->lock);
1408 				return (0);
1409 			}
1410 		}
1411 
1412 		/*
1413 		 * If the event is no longer registered then return
1414 		 * immediately
1415 		 */
1416 		if (!(dfc_event->event & hba->log_events)) {
1417 			mutex_exit(&log->lock);
1418 			return (0);
1419 		}
1420 	}
1421 	/* !!! An event has occurred since last_id !!! */
1422 
1423 	/* Check if event data is not being requested */
1424 	if (!size) {
1425 		/* If so, then just return the last event id */
1426 		dfc_event->last_id = log->event_id[i];
1427 
1428 		mutex_exit(&log->lock);
1429 		return (0);
1430 	}
1431 	/* !!! The requester wants the next event buffer !!! */
1432 
1433 	/* Calculate the current buffer boundaries */
1434 
1435 	/* Get last entry id saved */
1436 	last = log->count - 1;
1437 
1438 	/* Get oldest entry id and its index */
1439 	/* Check if buffer has already been filled once */
1440 	if (log->count >= log->size) {
1441 		first = log->count - log->size;
1442 		index = log->next;
1443 	} else {	/* Buffer not yet filled */
1444 		first = 0;
1445 		index = 0;
1446 	}
1447 
1448 	/* Check to see if the buffer has wrapped since the last event */
1449 	if (first > log->event_id[i]) {
1450 		/* Update last_id to the last known event */
1451 		dfc_event->last_id = log->event_id[i];
1452 
1453 		/* Try waiting again if we can */
1454 		goto wait_for_event;
1455 	}
1456 	/*
1457 	 * Check if requested first event is greater than actual. If so,
1458 	 * adjust for it.
1459 	 */
1460 	if (dfc_event->last_id > first) {
1461 		/* Adjust entry index to first requested message */
1462 		index += (dfc_event->last_id - first);
1463 		if (index >= log->size) {
1464 			index -= log->size;
1465 		}
1466 		first = dfc_event->last_id;
1467 	}
1468 	/* Get the total number of new messages */
1469 	count = last - first + 1;
1470 
1471 	/* Scan log for next event */
1472 	while (count--) {
1473 		if (++index >= log->size) {
1474 			index = 0;
1475 		}
1476 		entry = &log->entry[index];
1477 
1478 		if ((entry->msg->level == EMLXS_EVENT) &&
1479 		    (entry->msg->mask == dfc_event->event)) {
1480 			break;
1481 		}
1482 	}
1483 
1484 	/*
1485 	 * Check if no new event was found in the current log buffer.
1486 	 * This would indicate that the buffer wrapped since that last event
1487 	 */
1488 	if (!count) {
1489 		/* Update last_id to the last known event */
1490 		dfc_event->last_id = log->event_id[i];
1491 
1492 		/* Try waiting again if we can */
1493 		goto wait_for_event;
1494 	}
1495 	/* !!! Next event found !!! */
1496 
1497 	/* Copy the context buffer to the buffer provided */
1498 	if (entry->bp && entry->size) {
1499 		if (entry->size < size) {
1500 			size = entry->size;
1501 		}
1502 		if (ddi_copyout((void *) entry->bp, dfc_event->dataout, size,
1503 		    dfc_event->mode) != 0) {
1504 			mutex_exit(&log->lock);
1505 
1506 			return (DFC_COPYOUT_ERROR);
1507 		}
1508 		dfc_event->size = size;
1509 	}
1510 	dfc_event->last_id = entry->id;
1511 
1512 	mutex_exit(&log->lock);
1513 	return (0);
1514 
1515 } /* emlxs_get_dfc_event() */
1516 
1517 
1518 uint32_t
1519 emlxs_kill_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event)
1520 {
1521 	emlxs_hba_t *hba = HBA;
1522 	emlxs_msg_log_t *log;
1523 
1524 	/* Get the log file pointer */
1525 	log = &LOG;
1526 
1527 	mutex_enter(&log->lock);
1528 	dfc_event->pid = 0;
1529 	dfc_event->event = 0;
1530 	cv_broadcast(&log->lock_cv);
1531 	mutex_exit(&log->lock);
1532 
1533 	return (0);
1534 
1535 } /* emlxs_kill_dfc_event() */
1536 
1537 
1538 
1539 #endif	/* DFC_SUPPORT */
1540