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 #define	DEF_MSG_STRUCT	/* Needed for emlxs_messages.h in emlxs_msg.h */
28 #include <emlxs.h>
29 
30 
31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
32 EMLXS_MSG_DEF(EMLXS_MSG_C);
33 
34 uint32_t emlxs_log_size		= 2048;
35 uint32_t emlxs_log_debugs	= 0x7FFFFFFF;
36 uint32_t emlxs_log_notices	= 0xFFFFFFFF;
37 uint32_t emlxs_log_warnings	= 0xFFFFFFFF;
38 uint32_t emlxs_log_errors	= 0xFFFFFFFF;
39 
40 static uint32_t	emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg);
41 static uint32_t	emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg);
42 static void	emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry);
43 
44 
45 uint32_t
46 emlxs_msg_log_create(emlxs_hba_t *hba)
47 {
48 	emlxs_msg_log_t *log = &LOG;
49 	uint32_t size = sizeof (emlxs_msg_entry_t) * emlxs_log_size;
50 	char buf[40];
51 #ifdef MSI_SUPPORT
52 	ddi_intr_handle_t handle;
53 	uint32_t intr_pri;
54 	int32_t actual;
55 	uint32_t ret;
56 #endif /* MSI_SUPPORT */
57 	ddi_iblock_cookie_t iblock;
58 
59 	/* Check if log is already created */
60 	if (log->entry) {
61 		cmn_err(CE_WARN, "?%s%d: message log already created. log=%p",
62 		    DRIVER_NAME, hba->ddiinst, (void *)log);
63 		return (0);
64 	}
65 
66 	/* Clear the log */
67 	bzero(log, sizeof (emlxs_msg_log_t));
68 
69 	/* Allocate the memory needed for the log file */
70 	if (!(log->entry = (emlxs_msg_entry_t *)kmem_zalloc(size, KM_SLEEP))) {
71 		cmn_err(CE_WARN,
72 		    "?%s%d: Unable to allocate log memory. log=%p",
73 		    DRIVER_NAME, hba->ddiinst, (void *)log);
74 		return (0);
75 	}
76 
77 	/* Initialize */
78 	log->size = emlxs_log_size;
79 	log->instance = hba->ddiinst;
80 	log->start_time = emlxs_device.log_timestamp;
81 
82 	(void) sprintf(buf, "?%s%d_log_lock control variable", DRIVER_NAME,
83 	    hba->ddiinst);
84 	cv_init(&log->lock_cv, buf, CV_DRIVER, NULL);
85 
86 	(void) sprintf(buf, "?%s%d_log_lock mutex", DRIVER_NAME, hba->ddiinst);
87 
88 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
89 		/* Get the current interrupt block cookie */
90 		(void) ddi_get_iblock_cookie(hba->dip, (uint_t)EMLXS_INUMBER,
91 		    &iblock);
92 
93 		/* Create the log mutex lock */
94 		mutex_init(&log->lock, buf, MUTEX_DRIVER, (void *)iblock);
95 	}
96 #ifdef  MSI_SUPPORT
97 	else {
98 		/* Allocate a temporary interrupt handle */
99 		actual = 0;
100 		ret =
101 		    ddi_intr_alloc(hba->dip, &handle, DDI_INTR_TYPE_FIXED,
102 		    EMLXS_MSI_INUMBER, 1, &actual, DDI_INTR_ALLOC_NORMAL);
103 
104 		if (ret != DDI_SUCCESS || actual == 0) {
105 			cmn_err(CE_WARN,
106 			    "?%s%d: Unable to allocate temporary interrupt "
107 			    "handle. ret=%d actual=%d", DRIVER_NAME,
108 			    hba->ddiinst, ret, actual);
109 
110 			/* Free the log buffer */
111 			kmem_free(log->entry, size);
112 			bzero(log, sizeof (emlxs_msg_log_t));
113 
114 			return (0);
115 		}
116 
117 		/* Get the current interrupt priority */
118 		ret = ddi_intr_get_pri(handle, &intr_pri);
119 
120 		if (ret != DDI_SUCCESS) {
121 			cmn_err(CE_WARN,
122 			    "?%s%d: Unable to get interrupt priority. ret=%d",
123 			    DRIVER_NAME, hba->ddiinst, ret);
124 
125 			/* Free the log buffer */
126 			kmem_free(log->entry, size);
127 			bzero(log, sizeof (emlxs_msg_log_t));
128 
129 			return (0);
130 		}
131 
132 		/* Create the log mutex lock */
133 		mutex_init(&log->lock, buf, MUTEX_DRIVER,
134 		    (void *)((unsigned long)intr_pri));
135 
136 		/* Free the temporary handle */
137 		(void) ddi_intr_free(handle);
138 	}
139 #endif
140 
141 	return (1);
142 
143 }  /* emlxs_msg_log_create() */
144 
145 
146 uint32_t
147 emlxs_msg_log_destroy(emlxs_hba_t *hba)
148 {
149 	emlxs_msg_log_t *log = &LOG;
150 	uint32_t size;
151 	emlxs_msg_entry_t *entry;
152 	uint32_t i;
153 
154 	/* Check if log is already destroyed */
155 	if (!log->entry) {
156 		cmn_err(CE_WARN,
157 		    "?%s%d: message log already destroyed. log=%p",
158 		    DRIVER_NAME, hba->ddiinst, (void *)log);
159 
160 		return (1);
161 	}
162 
163 	/* If events are being logged there might be */
164 	/* threads waiting so release them */
165 	if (hba->log_events) {
166 		mutex_enter(&log->lock);
167 		hba->log_events = 0;
168 		cv_broadcast(&log->lock_cv);
169 		mutex_exit(&log->lock);
170 
171 		DELAYMS(1);
172 	}
173 
174 	/* Destroy the lock */
175 	mutex_destroy(&log->lock);
176 	cv_destroy(&log->lock_cv);
177 
178 	/* Free the context buffers */
179 	for (i = 0; i < log->size; i++) {
180 		entry = &log->entry[i];
181 
182 		if (entry->bp && entry->size) {
183 			kmem_free(entry->bp, entry->size);
184 		}
185 	}
186 
187 	/* Free the log buffer */
188 	size = sizeof (emlxs_msg_entry_t) * log->size;
189 	kmem_free(log->entry, size);
190 
191 	/* Clear the log */
192 	bzero(log, sizeof (emlxs_msg_log_t));
193 
194 	return (1);
195 
196 }  /* emlxs_msg_log_destroy() */
197 
198 void
199 emlxs_setup_abts_ct(emlxs_thread_t *et, void (*func) (),
200     emlxs_port_t *port, uint32_t rxid)
201 {
202 	et->func = func;
203 	et->arg1 = (void *)port;
204 	et->arg2 = (void *)((unsigned long)rxid);
205 
206 }  /* emlxs_setup_abts_ct */
207 
208 void
209 emlxs_abts_ct_thread(void *arg)
210 {
211 	emlxs_thread_t *et = (emlxs_thread_t *)arg;
212 	emlxs_port_t *port;
213 	void (*func) ();
214 	uint32_t rxid = 0;
215 
216 	func = et->func;
217 	port = (emlxs_port_t *)et->arg1;
218 	rxid = (uint32_t)((unsigned long)et->arg2);
219 
220 	func(port, rxid);
221 
222 	/*
223 	 * Allocated by the emlxs_msg_log()
224 	 */
225 	kmem_free(et, sizeof (emlxs_thread_t));
226 
227 	thread_exit();
228 
229 }  /* emlxs_abts_ct_thread */
230 
231 uint32_t
232 emlxs_msg_log(emlxs_port_t *port, const uint32_t fileno, const uint32_t line,
233     void *bp, uint32_t size, emlxs_msg_t *msg, char *buffer)
234 {
235 	emlxs_hba_t *hba = HBA;
236 	emlxs_msg_entry_t *entry;
237 	emlxs_msg_entry_t *entry2;
238 	clock_t time;
239 	emlxs_msg_log_t *log;
240 	uint32_t last;
241 	uint32_t mask;
242 	emlxs_msg_t *msg2;
243 	uint32_t rxid = 0;
244 	emlxs_thread_t *abts_ct_thread = NULL;
245 	uint32_t i;
246 
247 	/* Get the log file for this instance */
248 	log = &LOG;
249 
250 	/* Check if log is initialized */
251 	if (log->entry == NULL) {
252 
253 		if (port->vpi == 0) {
254 			cmn_err(CE_WARN,
255 			    "?%s%d: message log not created. log=%p",
256 			    DRIVER_NAME, hba->ddiinst, (void *)log);
257 		} else {
258 			cmn_err(CE_WARN,
259 			    "?%s%d.%d: message log not created. log=%p",
260 			    DRIVER_NAME, hba->ddiinst, port->vpi,
261 			    (void *)log);
262 		}
263 
264 		if (bp && size) {
265 			kmem_free(bp, size);
266 		}
267 
268 		return (1);
269 	}
270 
271 	mutex_enter(&log->lock);
272 
273 	/* Get the pointer to the last log entry */
274 	if (log->next == 0) {
275 		last = log->size - 1;
276 	} else {
277 		last = log->next - 1;
278 	}
279 	entry = &log->entry[last];
280 
281 	/* Check if this matches the last message */
282 	if ((entry->instance == log->instance) &&
283 	    (entry->vpi == port->vpi) &&
284 	    (entry->fileno == fileno) &&
285 	    (entry->line == line) &&
286 	    (entry->bp == bp) &&
287 	    (entry->size == size) &&
288 	    (entry->msg == msg) &&
289 	    (strcmp(entry->buffer, buffer) == 0)) {
290 		/* If the same message is being logged then increment */
291 		log->repeat++;
292 
293 		mutex_exit(&log->lock);
294 
295 		return (0);
296 	} else if (log->repeat) {
297 		/* Get the pointer to the next log entry */
298 		entry2 = &log->entry[log->next];
299 
300 		/* Increment and check the next entry index */
301 		if (++(log->next) >= log->size) {
302 			log->next = 0;
303 		}
304 
305 		switch (entry->msg->level) {
306 		case EMLXS_DEBUG:
307 			msg2 = &emlxs_debug_msg;
308 			break;
309 
310 		case EMLXS_NOTICE:
311 			msg2 = &emlxs_notice_msg;
312 			break;
313 
314 		case EMLXS_WARNING:
315 			msg2 = &emlxs_warning_msg;
316 			break;
317 
318 		case EMLXS_ERROR:
319 			msg2 = &emlxs_error_msg;
320 			break;
321 
322 		case EMLXS_PANIC:
323 			msg2 = &emlxs_panic_msg;
324 			break;
325 
326 		case EMLXS_EVENT:
327 			msg2 = &emlxs_event_msg;
328 			break;
329 		}
330 
331 		/* Check if we are about to overwrite an event entry */
332 		if (entry2->msg && (entry2->msg->level == EMLXS_EVENT)) {
333 			/* Check if this event has not been acquired */
334 			if (log->count > (hba->hba_event.last_id + log->size)) {
335 				hba->hba_event.missed++;
336 
337 				if ((entry2->msg->mask == EVT_CT) &&
338 				    !(entry2->flag & EMLX_EVENT_DONE)) {
339 					/* Abort exchange */
340 					rxid = *((uint32_t *)entry2->bp);
341 				}
342 			}
343 		}
344 
345 		/* Free the old context buffer since we are about to erase it */
346 		if (entry2->bp && entry2->size) {
347 			kmem_free(entry2->bp, entry2->size);
348 		}
349 
350 		/* Initialize */
351 		entry2->id = log->count++;
352 		entry2->fileno = entry->fileno;
353 		entry2->line = entry->line;
354 		entry2->bp = 0;
355 		entry2->size = 0;
356 		entry2->msg = msg2;
357 		entry2->instance = log->instance;
358 		entry2->vpi = port->vpi;
359 		entry2->flag = 0;
360 
361 		/* Save the additional info buffer */
362 		(void) sprintf(entry2->buffer,
363 		    "Last message repeated %d time(s).",
364 		    log->repeat);
365 
366 		/* Set the entry time stamp */
367 		(void) drv_getparm(LBOLT, &time);
368 		entry2->time = time - log->start_time;
369 
370 		log->repeat = 0;
371 	}
372 
373 	/* Get the pointer to the next log entry */
374 	entry = &log->entry[log->next];
375 
376 	/* Increment and check the next entry index */
377 	if (++(log->next) >= log->size) {
378 		log->next = 0;
379 	}
380 
381 	/* Check if we are about to overwrite an event entry */
382 	if (entry->msg && (entry->msg->level == EMLXS_EVENT)) {
383 		/* Check if this event has not been acquired */
384 		if (log->count > (hba->hba_event.last_id + log->size)) {
385 			hba->hba_event.missed++;
386 
387 			if ((entry->msg->mask == EVT_CT) &&
388 			    !(entry->flag & EMLX_EVENT_DONE)) {
389 
390 				/* Abort exchange */
391 				rxid = *((uint32_t *)entry->bp);
392 			}
393 		}
394 	}
395 
396 	/* Free the old context buffer since we are about to erase it */
397 	if (entry->bp && entry->size) {
398 		kmem_free(entry->bp, entry->size);
399 	}
400 
401 	/* Initialize */
402 	entry->id = log->count++;
403 	entry->fileno = fileno;
404 	entry->line = line;
405 	entry->bp = bp;
406 	entry->size = size;
407 	entry->msg = msg;
408 	entry->instance = log->instance;
409 	entry->vpi = port->vpi;
410 	entry->flag = 0;
411 
412 	/* Save the additional info buffer */
413 	(void) strncpy(entry->buffer, buffer, (MAX_LOG_INFO_LENGTH - 1));
414 	entry->buffer[MAX_LOG_INFO_LENGTH - 1] = 0;
415 
416 	/* Set the entry time stamp */
417 	(void) drv_getparm(LBOLT, &time);
418 	entry->time = time - log->start_time;
419 
420 	/* Check for a new event */
421 	if (msg->level == EMLXS_EVENT) {
422 		/* Update the event id */
423 		mask = msg->mask;
424 		for (i = 0; i < 32; i++) {
425 			if (mask & 0x01) {
426 				hba->hba_event.new++;
427 				log->event_id[i] = entry->id;
428 				cv_broadcast(&log->lock_cv);
429 				break;
430 			}
431 
432 			mask >>= 1;
433 		}
434 	}
435 
436 	mutex_exit(&log->lock);
437 
438 	if (rxid) {
439 		if (abts_ct_thread = (emlxs_thread_t *)
440 		    kmem_alloc(sizeof (emlxs_thread_t), KM_NOSLEEP)) {
441 
442 			emlxs_setup_abts_ct(abts_ct_thread,
443 			    emlxs_abort_ct_exchange, port, rxid);
444 
445 			/*
446 			 * The abts_ct_thread will be released by
447 			 * the emlxs_abts_ct_thread().
448 			 */
449 			thread_create(NULL, 0, emlxs_abts_ct_thread,
450 			    (char *)abts_ct_thread, 0,
451 			    &p0, TS_RUN, v.v_maxsyspri - 2);
452 		}
453 	}
454 
455 	return (0);
456 
457 }  /* emlxs_msg_log() */
458 
459 
460 static uint32_t
461 emlxs_msg_log_check(emlxs_port_t *port, emlxs_msg_t *msg)
462 {
463 	emlxs_hba_t *hba = HBA;
464 
465 	switch (msg->level) {
466 	case EMLXS_DEBUG:
467 		if (msg->mask & emlxs_log_debugs) {
468 			return (1);
469 		}
470 		break;
471 
472 	case EMLXS_NOTICE:
473 		if (msg->mask & emlxs_log_notices) {
474 			return (1);
475 		}
476 		break;
477 
478 	case EMLXS_WARNING:
479 		if (msg->mask & emlxs_log_warnings) {
480 			return (1);
481 		}
482 		break;
483 
484 	case EMLXS_ERROR:
485 		if (msg->mask & emlxs_log_errors) {
486 			return (1);
487 		}
488 		break;
489 
490 	case EMLXS_EVENT:
491 		if (msg->mask & hba->log_events) {
492 			return (1);
493 		}
494 #ifdef SAN_DIAG_SUPPORT
495 		if (msg->mask & port->sd_reg_events) {
496 			return (1);
497 		}
498 #endif /* SAN_DIAG_SUPPORT */
499 		break;
500 
501 	case EMLXS_PANIC:
502 		return (1);
503 	}
504 
505 	return (0);
506 
507 }  /* emlxs_msg_log_check() */
508 
509 
510 static uint32_t
511 emlxs_msg_print_check(emlxs_port_t *port, emlxs_msg_t *msg)
512 {
513 	emlxs_hba_t *hba = HBA;
514 	emlxs_config_t *cfg;
515 	uint32_t rval = 0;
516 
517 	cfg = &CFG;
518 
519 	switch (msg->level) {
520 	case EMLXS_DEBUG:
521 		if (msg->mask & cfg[CFG_CONSOLE_DEBUGS].current) {
522 			rval |= 2;
523 		}
524 
525 		if (msg->mask & cfg[CFG_LOG_DEBUGS].current) {
526 			rval |= 1;
527 		}
528 
529 		break;
530 
531 	case EMLXS_NOTICE:
532 		if (msg->mask & cfg[CFG_CONSOLE_NOTICES].current) {
533 			rval |= 2;
534 		}
535 
536 		if (msg->mask & cfg[CFG_LOG_NOTICES].current) {
537 			rval |= 1;
538 		}
539 
540 		break;
541 
542 	case EMLXS_WARNING:
543 		if (msg->mask & cfg[CFG_CONSOLE_WARNINGS].current) {
544 			rval |= 2;
545 		}
546 
547 		if (msg->mask & cfg[CFG_LOG_WARNINGS].current) {
548 			rval |= 1;
549 		}
550 
551 		break;
552 
553 	case EMLXS_ERROR:
554 		if (msg->mask & cfg[CFG_CONSOLE_ERRORS].current) {
555 			rval |= 2;
556 		}
557 
558 		if (msg->mask & cfg[CFG_LOG_ERRORS].current) {
559 			rval |= 1;
560 		}
561 		break;
562 
563 	case EMLXS_EVENT:
564 		/* Only print an event if it is being logged internally */
565 		if (msg->mask & hba->log_events) {
566 			if (msg->mask & cfg[CFG_CONSOLE_EVENTS].current) {
567 				rval |= 2;
568 			}
569 
570 			if (msg->mask & cfg[CFG_LOG_EVENTS].current) {
571 				rval |= 1;
572 			}
573 		}
574 		break;
575 
576 	case EMLXS_PANIC:
577 	default:
578 		rval |= 1;
579 
580 	}
581 
582 	return (rval);
583 
584 }  /* emlxs_msg_print_check() */
585 
586 
587 void
588 emlxs_msg_printf(emlxs_port_t *port, const uint32_t fileno,
589     const uint32_t line, void *bp, uint32_t size, emlxs_msg_t *msg,
590     const char *fmt, ...)
591 {
592 	emlxs_hba_t *hba = HBA;
593 #ifdef FMA_SUPPORT
594 	emlxs_port_t *phyport = &PPORT;
595 #endif	/* FMA_SUPPORT */
596 	va_list valist;
597 	char va_str[256];
598 	char msg_str[512];
599 	char *level;
600 	int32_t cmn_level;
601 	uint32_t rval;
602 	uint32_t logged;
603 	char driver[32];
604 
605 	va_str[0] = 0;
606 
607 	if (fmt) {
608 		va_start(valist, fmt);
609 		(void) vsprintf(va_str, fmt, valist);
610 		va_end(valist);
611 	}
612 
613 #ifdef FMA_SUPPORT
614 	/*
615 	 * Don't post fault event or/and error event to fmd
616 	 * if physical port was not bounded yet.
617 	 */
618 	if (phyport->flag & EMLXS_PORT_BOUND) {
619 		if (msg->fm_ereport_code) {
620 			emlxs_fm_ereport(hba, msg->fm_ereport_code);
621 		}
622 
623 		if (msg->fm_impact_code) {
624 			ddi_fm_service_impact(hba->dip, msg->fm_impact_code);
625 		}
626 	}
627 #endif	/* FMA_SUPPORT */
628 
629 	/* Check if msg should be logged */
630 	if ((logged = emlxs_msg_log_check(port, msg))) {
631 		/* Log the message */
632 		if (emlxs_msg_log(port, fileno, line, bp, size, msg, va_str)) {
633 			return;
634 		}
635 	}
636 
637 	/* Check if msg should be printed */
638 	if (rval = emlxs_msg_print_check(port, msg)) {
639 		cmn_level = CE_CONT;
640 
641 		switch (msg->level) {
642 		case EMLXS_DEBUG:
643 			level = "  DEBUG";
644 			break;
645 
646 		case EMLXS_NOTICE:
647 			level = " NOTICE";
648 			break;
649 
650 		case EMLXS_WARNING:
651 			level = "WARNING";
652 			break;
653 
654 		case EMLXS_ERROR:
655 			level = "  ERROR";
656 			break;
657 
658 		case EMLXS_PANIC:
659 			cmn_level = CE_PANIC;
660 			level = "  PANIC";
661 			break;
662 
663 		case EMLXS_EVENT:
664 			level = "  EVENT";
665 			break;
666 
667 		default:
668 			level = "UNKNOWN";
669 			break;
670 		}
671 
672 		if (port->vpi == 0) {
673 			(void) sprintf(driver, "%s%d", DRIVER_NAME,
674 			    hba->ddiinst);
675 		} else {
676 			(void) sprintf(driver, "%s%d.%d", DRIVER_NAME,
677 			    hba->ddiinst, port->vpi);
678 		}
679 
680 		/* Generate the message string */
681 		if (msg->buffer[0] != 0) {
682 			if (va_str[0] != 0) {
683 				(void) sprintf(msg_str,
684 				    "[%2X.%04X]%s:%7s:%4d: %s (%s)\n", fileno,
685 				    line, driver, level, msg->id, msg->buffer,
686 				    va_str);
687 			} else {
688 				(void) sprintf(msg_str,
689 				    "[%2X.%04X]%s:%7s:%4d: %s\n",
690 				    fileno, line, driver, level, msg->id,
691 				    msg->buffer);
692 			}
693 		} else {
694 			if (va_str[0] != 0) {
695 				(void) sprintf(msg_str,
696 				    "[%2X.%04X]%s:%7s:%4d: (%s)\n", fileno,
697 				    line, driver, level, msg->id, va_str);
698 			} else {
699 				(void) sprintf(msg_str,
700 				    "[%2X.%04X]%s:%7s:%4d\n",
701 				    fileno, line, driver, level, msg->id);
702 			}
703 		}
704 
705 		switch (rval) {
706 		case 1:	/* MESSAGE LOG ONLY */
707 			/* Message log & console, if system booted in */
708 			/* verbose mode (CE_CONT only) */
709 			cmn_err(cmn_level, "?%s", msg_str);
710 			break;
711 
712 		case 2:	/* CONSOLE ONLY */
713 			cmn_err(cmn_level, "^%s", msg_str);
714 			break;
715 
716 		case 3:	/* CONSOLE AND MESSAGE LOG */
717 			cmn_err(cmn_level, "%s", msg_str);
718 			break;
719 
720 		}
721 
722 	}
723 
724 	/* If message was not logged, then free any context buffer provided */
725 	if (!logged && bp && size) {
726 		kmem_free(bp, size);
727 	}
728 
729 	return;
730 
731 }  /* emlxs_msg_printf() */
732 
733 
734 uint32_t
735 emlxs_msg_log_get(emlxs_hba_t *hba, emlxs_log_req_t *req,
736     emlxs_log_resp_t *resp)
737 {
738 	emlxs_msg_log_t *log;
739 	uint32_t first;
740 	uint32_t last;
741 	uint32_t count;
742 	uint32_t index;
743 	uint32_t i;
744 	char *resp_buf;
745 
746 	log = &LOG;
747 
748 	mutex_enter(&log->lock);
749 
750 	/* Check if buffer is empty */
751 	if (log->count == 0) {
752 		/* If so, exit now */
753 		resp->first = 0;
754 		resp->last = 0;
755 		resp->count = 0;
756 		mutex_exit(&log->lock);
757 
758 		return (1);
759 	}
760 
761 	/* Get current log entry ranges */
762 
763 	/* Get last entry id saved */
764 	last = log->count - 1;
765 
766 	/* Check if request is out of current range */
767 	if (req->first > last) {
768 		/* if so, exit now */
769 		resp->first = last;
770 		resp->last = last;
771 		resp->count = 0;
772 		mutex_exit(&log->lock);
773 
774 		return (0);
775 	}
776 
777 	/* Get oldest entry id and its index */
778 
779 	/* Check if buffer has already been filled once */
780 	if (log->count >= log->size) {
781 		first = log->count - log->size;
782 		index = log->next;
783 	} else {	/* Buffer not yet filled */
784 
785 		first = 0;
786 		index = 0;
787 	}
788 
789 	/* Check if requested first message is greater than actual. */
790 	/* If so, adjust for it.  */
791 	if (req->first > first) {
792 		/* Adjust entry index to first requested message */
793 		index += (req->first - first);
794 		if (index >= log->size) {
795 			index -= log->size;
796 		}
797 
798 		first = req->first;
799 	}
800 
801 	/* Get the total number of messages available for return */
802 	count = last - first + 1;
803 
804 	/* Check if requested count is less than actual.  If so, adjust it. */
805 	if (req->count < count) {
806 		count = req->count;
807 	}
808 
809 	/* Fill in the response header */
810 	resp->count = count;
811 	resp->first = first;
812 	resp->last = last;
813 
814 	/* Fill the response buffer */
815 	resp_buf = (char *)resp + sizeof (emlxs_log_resp_t);
816 	for (i = 0; i < count; i++) {
817 		emlxs_msg_sprintf(resp_buf, &log->entry[index]);
818 
819 		/* Increment the response buffer */
820 		resp_buf += MAX_LOG_MSG_LENGTH;
821 
822 		/* Increment index */
823 		if (++index >= log->size) {
824 			index = 0;
825 		}
826 	}
827 
828 	mutex_exit(&log->lock);
829 
830 	return (1);
831 
832 }  /* emlxs_msg_log_get() */
833 
834 
835 
836 static void
837 emlxs_msg_sprintf(char *buffer, emlxs_msg_entry_t *entry)
838 {
839 	char *level;
840 	emlxs_msg_t *msg;
841 	uint32_t secs;
842 	uint32_t hsecs;
843 	char buf[256];
844 	uint32_t buflen;
845 	char driver[32];
846 
847 	msg = entry->msg;
848 	hsecs = (entry->time % 100);
849 	secs = entry->time / 100;
850 
851 	switch (msg->level) {
852 	case EMLXS_DEBUG:
853 		level = "  DEBUG";
854 		break;
855 
856 	case EMLXS_NOTICE:
857 		level = " NOTICE";
858 		break;
859 
860 	case EMLXS_WARNING:
861 		level = "WARNING";
862 		break;
863 
864 	case EMLXS_ERROR:
865 		level = "  ERROR";
866 		break;
867 
868 	case EMLXS_PANIC:
869 		level = "  PANIC";
870 		break;
871 
872 	case EMLXS_EVENT:
873 		level = "  EVENT";
874 		break;
875 
876 	default:
877 		level = "UNKNOWN";
878 		break;
879 	}
880 
881 	if (entry->vpi == 0) {
882 		(void) sprintf(driver, "%s%d", DRIVER_NAME, entry->instance);
883 	} else {
884 		(void) sprintf(driver, "%s%d.%d", DRIVER_NAME, entry->instance,
885 		    entry->vpi);
886 	}
887 
888 	/* Generate the message string */
889 	if (msg->buffer[0] != 0) {
890 		if (entry->buffer[0] != 0) {
891 			(void) sprintf(buf,
892 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s (%s)\n",
893 			    secs, hsecs, entry->id, entry->fileno,
894 			    entry->line, driver, level, msg->id, msg->buffer,
895 			    entry->buffer);
896 
897 		} else {
898 			(void) sprintf(buf,
899 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: %s\n", secs,
900 			    hsecs, entry->id, entry->fileno, entry->line,
901 			    driver, level, msg->id, msg->buffer);
902 		}
903 	} else {
904 		if (entry->buffer[0] != 0) {
905 			(void) sprintf(buf,
906 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d: (%s)\n",
907 			    secs, hsecs, entry->id, entry->fileno,
908 			    entry->line, driver, level, msg->id,
909 			    entry->buffer);
910 		} else {
911 			(void) sprintf(buf,
912 			    "%8d.%02d: %6d:[%2X.%04X]%s:%7s:%4d\n",
913 			    secs, hsecs, entry->id, entry->fileno,
914 			    entry->line, driver, level, msg->id);
915 		}
916 	}
917 
918 	bzero(buffer, MAX_LOG_MSG_LENGTH);
919 	buflen = strlen(buf);
920 
921 	if (buflen > (MAX_LOG_MSG_LENGTH - 1)) {
922 		(void) strncpy(buffer, buf, (MAX_LOG_MSG_LENGTH - 2));
923 		buffer[MAX_LOG_MSG_LENGTH - 2] = '\n';
924 	} else {
925 		(void) strncpy(buffer, buf, buflen);
926 	}
927 
928 	return;
929 
930 }  /* emlxs_msg_sprintf() */
931 
932 
933 
934 
935 void
936 emlxs_log_rscn_event(emlxs_port_t *port, uint8_t *payload, uint32_t size)
937 {
938 #ifdef DFC_SUPPORT
939 	emlxs_hba_t *hba = HBA;
940 	uint8_t *bp;
941 	uint32_t *ptr;
942 
943 	/* Check if the event is being requested */
944 	if (!(hba->log_events & EVT_RSCN)) {
945 		return;
946 	}
947 
948 	if (size > MAX_RSCN_PAYLOAD) {
949 		size = MAX_RSCN_PAYLOAD;
950 	}
951 
952 	size += sizeof (uint32_t);
953 
954 	/* Save a copy of the payload for the event log */
955 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
956 		return;
957 	}
958 
959 
960 	/*
961 	 * Buffer Format:
962 	 *	word[0] = DID of the RSCN
963 	 *	word[1] = RSCN Payload
964 	 */
965 	ptr = (uint32_t *)bp;
966 	*ptr++ = port->did;
967 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
968 
969 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_rscn_event,
970 	    "bp=%p size=%d", bp, size);
971 
972 #endif /* DFC_SUPPORT */
973 	return;
974 
975 }  /* emlxs_log_rscn_event() */
976 
977 
978 void
979 emlxs_log_vportrscn_event(emlxs_port_t *port, uint8_t *payload, uint32_t size)
980 {
981 #ifdef DFC_SUPPORT
982 	emlxs_hba_t *hba = HBA;
983 	uint8_t *bp;
984 	uint8_t *ptr;
985 
986 	/* Check if the event is being requested */
987 	if (!(hba->log_events & EVT_VPORTRSCN)) {
988 		return;
989 	}
990 
991 	if (size > MAX_RSCN_PAYLOAD) {
992 		size = MAX_RSCN_PAYLOAD;
993 	}
994 
995 	/* Save a copy of the payload for the event log */
996 	if (!(bp =
997 	    (uint8_t *)kmem_alloc(size + sizeof (NAME_TYPE), KM_NOSLEEP))) {
998 		return;
999 	}
1000 
1001 
1002 	/*
1003 	 * Buffer Format:
1004 	 *	word[0 - 4] = WWPN of the RSCN
1005 	 *	word[5] = RSCN Payload
1006 	 */
1007 	ptr = bp;
1008 	bcopy(&port->wwpn, ptr, sizeof (NAME_TYPE));
1009 	ptr += sizeof (NAME_TYPE);
1010 	bcopy(payload, ptr, size);
1011 
1012 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size + sizeof (NAME_TYPE),
1013 	    &emlxs_vportrscn_event, "bp=%p size=%d", bp, size);
1014 
1015 #endif /* DFC_SUPPORT */
1016 	return;
1017 
1018 }  /* emlxs_log_vportrscn_event() */
1019 
1020 
1021 uint32_t
1022 emlxs_log_ct_event(emlxs_port_t *port, uint8_t *payload, uint32_t size,
1023     uint32_t rxid)
1024 {
1025 #ifdef DFC_SUPPORT
1026 	emlxs_hba_t *hba = HBA;
1027 	uint8_t *bp;
1028 	uint32_t *ptr;
1029 
1030 	/* Check if the event is being requested */
1031 	if (!(hba->log_events & EVT_CT)) {
1032 		return (1);
1033 	}
1034 
1035 	if (size > MAX_CT_PAYLOAD) {
1036 		size = MAX_CT_PAYLOAD;
1037 	}
1038 
1039 	size += sizeof (uint32_t);
1040 
1041 	/* Save a copy of the payload for the event log */
1042 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1043 		return (1);
1044 	}
1045 
1046 	/*
1047 	 * Buffer Format:
1048 	 *	word[0] = RXID tag for outgoing reply to this CT request
1049 	 *	word[1] = CT Payload
1050 	 */
1051 	ptr = (uint32_t *)bp;
1052 	*ptr++ = rxid;
1053 
1054 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
1055 
1056 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_ct_event,
1057 	    "bp=%p size=%d rxid=%x", bp, size, rxid);
1058 
1059 
1060 	return (0);
1061 #else
1062 
1063 	return (1);
1064 
1065 #endif /* DFC_SUPPORT */
1066 
1067 }  /* emlxs_log_ct_event() */
1068 
1069 
1070 void
1071 emlxs_log_link_event(emlxs_port_t *port)
1072 {
1073 #ifdef DFC_SUPPORT
1074 	emlxs_hba_t *hba = HBA;
1075 	uint8_t *bp;
1076 	dfc_linkinfo_t *linkinfo;
1077 	uint8_t *byte;
1078 	uint8_t *linkspeed;
1079 	uint8_t *liptype;
1080 	uint8_t *resv1;
1081 	uint8_t *resv2;
1082 	uint32_t size;
1083 
1084 	/* Check if the event is being requested */
1085 	/*
1086 	 * if(!(hba->log_events & EVT_LINK)) { return; }
1087 	 */
1088 	size = sizeof (dfc_linkinfo_t) + sizeof (uint32_t);
1089 
1090 	/* Save a copy of the buffer for the event log */
1091 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1092 		return;
1093 	}
1094 
1095 	/*
1096 	 * Buffer Format:
1097 	 *	word[0] = Linkspeed:8
1098 	 *	word[0] = LIP_type:8
1099 	 *	word[0] = resv1:8
1100 	 *	word[0] = resv2:8
1101 	 *	word[1] = dfc_linkinfo_t data
1102 	 */
1103 	byte = (uint8_t *)bp;
1104 	linkspeed = &byte[0];
1105 	liptype = &byte[1];
1106 	resv1 = &byte[2];
1107 	resv2 = &byte[3];
1108 	linkinfo = (dfc_linkinfo_t *)&byte[4];
1109 
1110 	*resv1 = 0;
1111 	*resv2 = 0;
1112 
1113 	if (hba->state <= FC_LINK_DOWN) {
1114 		*linkspeed = 0;
1115 		*liptype = 0;
1116 	} else {
1117 		/* Set linkspeed */
1118 		if (hba->linkspeed == LA_2GHZ_LINK) {
1119 			*linkspeed = HBA_PORTSPEED_2GBIT;
1120 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
1121 			*linkspeed = HBA_PORTSPEED_4GBIT;
1122 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
1123 			*linkspeed = HBA_PORTSPEED_8GBIT;
1124 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
1125 			*linkspeed = HBA_PORTSPEED_10GBIT;
1126 		} else {
1127 			*linkspeed = HBA_PORTSPEED_1GBIT;
1128 		}
1129 
1130 		/* Set LIP type */
1131 		*liptype = port->lip_type;
1132 	}
1133 
1134 	bzero(linkinfo, sizeof (dfc_linkinfo_t));
1135 
1136 	linkinfo->a_linkEventTag = hba->link_event_tag;
1137 	linkinfo->a_linkUp = HBASTATS.LinkUp;
1138 	linkinfo->a_linkDown = HBASTATS.LinkDown;
1139 	linkinfo->a_linkMulti = HBASTATS.LinkMultiEvent;
1140 
1141 	if (hba->state <= FC_LINK_DOWN) {
1142 		linkinfo->a_linkState = LNK_DOWN;
1143 		linkinfo->a_DID = port->prev_did;
1144 	} else if (hba->state < FC_READY) {
1145 		linkinfo->a_linkState = LNK_DISCOVERY;
1146 	} else {
1147 		linkinfo->a_linkState = LNK_READY;
1148 	}
1149 
1150 	if (linkinfo->a_linkState != LNK_DOWN) {
1151 		if (hba->topology == TOPOLOGY_LOOP) {
1152 			if (hba->flag & FC_FABRIC_ATTACHED) {
1153 				linkinfo->a_topology = LNK_PUBLIC_LOOP;
1154 			} else {
1155 				linkinfo->a_topology = LNK_LOOP;
1156 			}
1157 
1158 			linkinfo->a_alpa = port->did & 0xff;
1159 			linkinfo->a_DID = linkinfo->a_alpa;
1160 			linkinfo->a_alpaCnt = port->alpa_map[0];
1161 
1162 			if (linkinfo->a_alpaCnt > 127) {
1163 				linkinfo->a_alpaCnt = 127;
1164 			}
1165 
1166 			bcopy((void *)&port->alpa_map[1], linkinfo->a_alpaMap,
1167 			    linkinfo->a_alpaCnt);
1168 		} else {
1169 			if (port->node_count == 1) {
1170 				linkinfo->a_topology = LNK_PT2PT;
1171 			} else {
1172 				linkinfo->a_topology = LNK_FABRIC;
1173 			}
1174 
1175 			linkinfo->a_DID = port->did;
1176 		}
1177 	}
1178 
1179 	bcopy(&hba->wwpn, linkinfo->a_wwpName, 8);
1180 	bcopy(&hba->wwnn, linkinfo->a_wwnName, 8);
1181 
1182 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_link_event,
1183 	    "bp=%p size=%d tag=%x", bp, size, hba->link_event_tag);
1184 
1185 #endif /* DFC_SUPPORT */
1186 
1187 	return;
1188 
1189 }  /* emlxs_log_link_event() */
1190 
1191 
1192 void
1193 emlxs_log_dump_event(emlxs_port_t *port, uint8_t *buffer, uint32_t size)
1194 {
1195 #ifdef DFC_SUPPORT
1196 	emlxs_hba_t *hba = HBA;
1197 	uint8_t *bp;
1198 
1199 	/* Check if the event is being requested */
1200 	if (!(hba->log_events & EVT_DUMP)) {
1201 #ifdef DUMP_SUPPORT
1202 		/* Schedule a dump thread */
1203 		emlxs_dump(hba, EMLXS_DRV_DUMP, 0, 0);
1204 #endif /* DUMP_SUPPORT */
1205 		return;
1206 	}
1207 
1208 	if (buffer && size) {
1209 		/* Save a copy of the buffer for the event log */
1210 		if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1211 			return;
1212 		}
1213 
1214 		bcopy(buffer, bp, size);
1215 	} else {
1216 		bp = NULL;
1217 		size = 0;
1218 	}
1219 
1220 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_dump_event,
1221 	    "bp=%p size=%d", bp, size);
1222 #else
1223 
1224 #ifdef DUMP_SUPPORT
1225 	/* Schedule a dump thread */
1226 	emlxs_dump(hba, EMLXS_DRV_DUMP, 0, 0);
1227 #endif /* DUMP_SUPPORT */
1228 
1229 #endif /* DFC_SUPPORT */
1230 
1231 	return;
1232 
1233 }  /* emlxs_log_dump_event() */
1234 
1235 
1236 extern void
1237 emlxs_log_temp_event(emlxs_port_t *port, uint32_t type, uint32_t temp)
1238 {
1239 	emlxs_hba_t *hba = HBA;
1240 
1241 #ifdef DFC_SUPPORT
1242 	uint32_t *bp;
1243 	uint32_t size;
1244 
1245 	/* Check if the event is being requested */
1246 	if (!(hba->log_events & EVT_TEMP)) {
1247 #ifdef DUMP_SUPPORT
1248 		/* Schedule a dump thread */
1249 		emlxs_dump(hba, EMLXS_TEMP_DUMP, type, temp);
1250 #endif /* DUMP_SUPPORT */
1251 		return;
1252 	}
1253 
1254 	size = 2 * sizeof (uint32_t);
1255 
1256 	if (!(bp = (uint32_t *)kmem_alloc(size, KM_NOSLEEP))) {
1257 		return;
1258 	}
1259 
1260 	bp[0] = type;
1261 	bp[1] = temp;
1262 
1263 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_temp_event,
1264 	    "type=%x temp=%d bp=%p size=%d", type, temp, bp, size);
1265 
1266 #else /* !DFC_SUPPORT */
1267 
1268 #ifdef DUMP_SUPPORT
1269 	/* Schedule a dump thread */
1270 	emlxs_dump(hba, EMLXS_TEMP_DUMP, type, temp);
1271 #endif /* DUMP_SUPPORT */
1272 
1273 #endif /* DFC_SUPPORT */
1274 
1275 	return;
1276 
1277 }  /* emlxs_log_temp_event() */
1278 
1279 
1280 
1281 extern void
1282 emlxs_log_fcoe_event(emlxs_port_t *port, menlo_init_rsp_t *init_rsp)
1283 {
1284 #ifdef DFC_SUPPORT
1285 	emlxs_hba_t *hba = HBA;
1286 	uint8_t *bp;
1287 	uint32_t size;
1288 
1289 	/* Check if the event is being requested */
1290 	if (!(hba->log_events & EVT_FCOE)) {
1291 		return;
1292 	}
1293 
1294 	/* Check if this is a FCOE adapter */
1295 	if (hba->model_info.device_id != PCI_DEVICE_ID_LP21000_M) {
1296 		return;
1297 	}
1298 
1299 	size = sizeof (menlo_init_rsp_t);
1300 
1301 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1302 		return;
1303 	}
1304 
1305 	bcopy((uint8_t *)init_rsp, bp, size);
1306 
1307 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_fcoe_event,
1308 	    "bp=%p size=%d", bp, size);
1309 #endif /* DFC_SUPPORT */
1310 
1311 	return;
1312 
1313 }  /* emlxs_log_fcoe_event() */
1314 
1315 
1316 #ifdef SAN_DIAG_SUPPORT
1317 extern void
1318 emlxs_log_sd_basic_els_event(emlxs_port_t *port, uint32_t subcat,
1319     HBA_WWN *portname, HBA_WWN *nodename)
1320 {
1321 	struct sd_plogi_rcv_v0	*bp;
1322 	uint32_t		size;
1323 
1324 	/* Check if the event is being requested */
1325 	if (!(port->sd_reg_events & EVT_SD_ELS))
1326 		return;
1327 
1328 	size = sizeof (struct sd_plogi_rcv_v0);
1329 
1330 	if (!(bp = (struct sd_plogi_rcv_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1331 		return;
1332 
1333 	/*
1334 	 * we are using version field to store subtype, libdfc
1335 	 * will fix this up before returning data to app.
1336 	 */
1337 	bp->sd_plogir_version = subcat;
1338 	bcopy((uint8_t *)portname, (uint8_t *)&bp->sd_plogir_portname,
1339 	    sizeof (HBA_WWN));
1340 	bcopy((uint8_t *)nodename, (uint8_t *)&bp->sd_plogir_nodename,
1341 	    sizeof (HBA_WWN));
1342 
1343 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_els_event,
1344 	    "bp=%p size=%d", bp, size);
1345 
1346 	return;
1347 
1348 } /* emlxs_log_sd_basic_els_event() */
1349 
1350 
1351 extern void
1352 emlxs_log_sd_prlo_event(emlxs_port_t *port, HBA_WWN *remoteport)
1353 {
1354 	struct sd_prlo_rcv_v0	*bp;
1355 	uint32_t		size;
1356 
1357 	/* Check if the event is being requested */
1358 	if (!(port->sd_reg_events & EVT_SD_ELS))
1359 		return;
1360 
1361 	size = sizeof (struct sd_prlo_rcv_v0);
1362 
1363 	if (!(bp = (struct sd_prlo_rcv_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1364 		return;
1365 
1366 	/*
1367 	 * we are using version field to store subtype, libdfc
1368 	 * will fix this up before returning data to app.
1369 	 */
1370 	bp->sd_prlor_version = SD_ELS_SUBCATEGORY_PRLO_RCV;
1371 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_prlor_remoteport,
1372 	    sizeof (HBA_WWN));
1373 
1374 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_els_event,
1375 	    "bp=%p size=%d", bp, size);
1376 
1377 	return;
1378 
1379 } /* emlxs_log_sd_prlo_event() */
1380 
1381 
1382 extern void
1383 emlxs_log_sd_lsrjt_event(emlxs_port_t *port, HBA_WWN *remoteport,
1384     uint32_t orig_cmd, uint32_t reason, uint32_t reason_expl)
1385 {
1386 	struct sd_lsrjt_rcv_v0	*bp;
1387 	uint32_t		size;
1388 
1389 	/* Check if the event is being requested */
1390 	if (!(port->sd_reg_events & EVT_SD_ELS))
1391 		return;
1392 
1393 	size = sizeof (struct sd_lsrjt_rcv_v0);
1394 
1395 	if (!(bp = (struct sd_lsrjt_rcv_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1396 		return;
1397 
1398 	/*
1399 	 * we are using version field to store subtype, libdfc
1400 	 * will fix this up before returning data to app.
1401 	 */
1402 	bp->sd_lsrjtr_version = SD_ELS_SUBCATEGORY_LSRJT_RCV;
1403 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_lsrjtr_remoteport,
1404 	    sizeof (HBA_WWN));
1405 	bp->sd_lsrjtr_original_cmd = orig_cmd;
1406 	bp->sd_lsrjtr_reasoncode = reason;
1407 	bp->sd_lsrjtr_reasoncodeexpl = reason_expl;
1408 
1409 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_els_event,
1410 	    "bp=%p size=%d", bp, size);
1411 
1412 	return;
1413 
1414 } /* emlxs_log_sd_lsrjt_event() */
1415 
1416 
1417 
1418 extern void
1419 emlxs_log_sd_fc_bsy_event(emlxs_port_t *port, HBA_WWN *remoteport)
1420 {
1421 	struct sd_pbsy_rcv_v0	*bp;
1422 	uint32_t		size;
1423 
1424 	/* Check if the event is being requested */
1425 	if (!(port->sd_reg_events & EVT_SD_FABRIC))
1426 		return;
1427 
1428 	size = sizeof (struct sd_pbsy_rcv_v0);
1429 
1430 	if (!(bp = (struct sd_pbsy_rcv_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1431 		return;
1432 
1433 	/*
1434 	 * we are using version field to store subtype, libdfc
1435 	 * will fix this up before returning data to app.
1436 	 */
1437 	if (remoteport == NULL)
1438 		bp->sd_pbsyr_evt_version = SD_FABRIC_SUBCATEGORY_FABRIC_BUSY;
1439 	else
1440 	{
1441 		bp->sd_pbsyr_evt_version = SD_FABRIC_SUBCATEGORY_PORT_BUSY;
1442 		bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_pbsyr_rport,
1443 		    sizeof (HBA_WWN));
1444 	}
1445 
1446 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_fabric_event,
1447 	    "bp=%p size=%d", bp, size);
1448 
1449 	return;
1450 
1451 } /* emlxs_log_sd_fc_bsy_event() */
1452 
1453 
1454 extern void
1455 emlxs_log_sd_fc_rdchk_event(emlxs_port_t *port, HBA_WWN *remoteport,
1456     uint32_t lun, uint32_t opcode, uint32_t fcp_param)
1457 {
1458 	struct sd_fcprdchkerr_v0	*bp;
1459 	uint32_t			size;
1460 
1461 	/* Check if the event is being requested */
1462 	if (!(port->sd_reg_events & EVT_SD_FABRIC))
1463 		return;
1464 
1465 	size = sizeof (struct sd_fcprdchkerr_v0);
1466 
1467 	if (!(bp = (struct sd_fcprdchkerr_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1468 		return;
1469 
1470 	/*
1471 	 * we are using version field to store subtype, libdfc
1472 	 * will fix this up before returning data to app.
1473 	 */
1474 	bp->sd_fcprdchkerr_version = SD_FABRIC_SUBCATEGORY_FCPRDCHKERR;
1475 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_fcprdchkerr_rport,
1476 	    sizeof (HBA_WWN));
1477 	bp->sd_fcprdchkerr_lun = lun;
1478 	bp->sd_fcprdchkerr_opcode = opcode;
1479 	bp->sd_fcprdchkerr_fcpiparam = fcp_param;
1480 
1481 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_fabric_event,
1482 	    "bp=%p size=%d", bp, size);
1483 
1484 	return;
1485 
1486 } /* emlxs_log_sd_rdchk_event() */
1487 
1488 
1489 extern void
1490 emlxs_log_sd_scsi_event(emlxs_port_t *port, uint32_t type,
1491     HBA_WWN *remoteport, int32_t lun)
1492 {
1493 	struct sd_scsi_generic_v0	*bp;
1494 	uint32_t			size;
1495 
1496 	/* Check if the event is being requested */
1497 	if (!(port->sd_reg_events & EVT_SD_SCSI))
1498 		return;
1499 
1500 	size = sizeof (struct sd_scsi_generic_v0);
1501 
1502 	if (!(bp = (struct sd_scsi_generic_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1503 		return;
1504 
1505 	/*
1506 	 * we are using version field to store subtype, libdfc
1507 	 * will fix this up before returning data to app.
1508 	 */
1509 	bp->sd_scsi_generic_version = type;
1510 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_scsi_generic_rport,
1511 	    sizeof (HBA_WWN));
1512 	bp->sd_scsi_generic_lun = lun;
1513 
1514 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_scsi_event,
1515 	    "bp=%p size=%d", bp, size);
1516 
1517 	return;
1518 
1519 } /* emlxs_log_sd_scsi_event() */
1520 
1521 
1522 extern void
1523 emlxs_log_sd_scsi_check_event(emlxs_port_t *port, HBA_WWN *remoteport,
1524     uint32_t lun, uint32_t cmdcode, uint32_t sensekey,
1525     uint32_t asc, uint32_t ascq)
1526 {
1527 	struct sd_scsi_checkcond_v0	*bp;
1528 	uint32_t			size;
1529 
1530 	/* Check if the event is being requested */
1531 	if (!(port->sd_reg_events & EVT_SD_SCSI))
1532 		return;
1533 
1534 	size = sizeof (struct sd_scsi_checkcond_v0);
1535 
1536 	if (!(bp = (struct sd_scsi_checkcond_v0 *)kmem_alloc(size, KM_NOSLEEP)))
1537 		return;
1538 
1539 	/*
1540 	 * we are using version field to store subtype, libdfc
1541 	 * will fix this up before returning data to app.
1542 	 */
1543 	bp->sd_scsi_checkcond_version = SD_SCSI_SUBCATEGORY_CHECKCONDITION;
1544 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_scsi_checkcond_rport,
1545 	    sizeof (HBA_WWN));
1546 	bp->sd_scsi_checkcond_lun = lun;
1547 	bp->sd_scsi_checkcond_cmdcode = cmdcode;
1548 	bp->sd_scsi_checkcond_sensekey = sensekey;
1549 	bp->sd_scsi_checkcond_asc = asc;
1550 	bp->sd_scsi_checkcond_ascq = ascq;
1551 
1552 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_sd_scsi_event,
1553 	    "bp=%p size=%d", bp, size);
1554 
1555 }
1556 #endif	/* SAN_DIAG_SUPPORT */
1557 
1558 
1559 extern void
1560 emlxs_log_async_event(emlxs_port_t *port, IOCB *iocb)
1561 {
1562 	uint8_t *bp;
1563 	uint32_t size;
1564 
1565 	/* ASYNC_STATUS_CN response size */
1566 	size = 64;
1567 
1568 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
1569 		return;
1570 	}
1571 
1572 	bcopy((uint8_t *)iocb, bp, size);
1573 
1574 	EMLXS_MSGF(EMLXS_CONTEXT_BP, bp, size, &emlxs_async_event,
1575 	    "bp=%p size=%d", bp, size);
1576 
1577 }  /* emlxs_log_async_event() */
1578 
1579 #ifdef DFC_SUPPORT
1580 
1581 extern uint32_t
1582 emlxs_get_dfc_eventinfo(emlxs_port_t *port, HBA_EVENTINFO *eventinfo,
1583     uint32_t *eventcount, uint32_t *missed)
1584 {
1585 	emlxs_hba_t *hba = HBA;
1586 	emlxs_msg_log_t *log;
1587 	uint32_t first;
1588 	uint32_t last;
1589 	uint32_t count;
1590 	uint32_t index;
1591 	emlxs_msg_entry_t *entry;
1592 	dfc_linkinfo_t *linkinfo;
1593 	uint32_t *word;
1594 	uint8_t *byte;
1595 	uint8_t linkspeed;
1596 	uint8_t liptype;
1597 	fc_affected_id_t *aid;
1598 	uint32_t max_events;
1599 	uint32_t events;
1600 	emlxs_hba_event_t *hba_event;
1601 
1602 	if (!eventinfo || !eventcount || !missed) {
1603 		return (DFC_ARG_NULL);
1604 	}
1605 
1606 	hba_event = &hba->hba_event;
1607 	max_events = *eventcount;
1608 	*eventcount = 0;
1609 
1610 	log = &LOG;
1611 
1612 	mutex_enter(&log->lock);
1613 
1614 	/* Check if log is empty */
1615 	if (log->count == 0) {
1616 		/* Make sure everything is initialized */
1617 		hba_event->new = 0;
1618 		hba_event->missed = 0;
1619 		hba_event->last_id = 0;
1620 
1621 		mutex_exit(&log->lock);
1622 		return (0);
1623 	}
1624 
1625 	/* Safety check */
1626 	if (hba_event->last_id > (log->count - 1)) {
1627 		hba_event->last_id = log->count - 1;
1628 	}
1629 
1630 	/* Account for missed events */
1631 	if (hba_event->new > hba_event->missed) {
1632 		hba_event->new -= hba_event->missed;
1633 	} else {
1634 		hba_event->new = 0;
1635 	}
1636 
1637 	*missed = hba_event->missed;
1638 	hba_event->missed = 0;
1639 
1640 	if (!hba_event->new) {
1641 		hba_event->last_id = log->count;
1642 		mutex_exit(&log->lock);
1643 		return (0);
1644 	}
1645 
1646 	/* A new event has occurred since last acquisition */
1647 	/* Calculate the current buffer boundaries */
1648 
1649 	/* Get last entry id saved */
1650 	last = log->count - 1;
1651 
1652 	/* Get oldest entry id and its index */
1653 	/* Check if buffer has already been filled once */
1654 	if (log->count >= log->size) {
1655 		first = log->count - log->size;
1656 		index = log->next;
1657 	} else {	/* Buffer not yet filled */
1658 
1659 		first = 0;
1660 		index = 0;
1661 	}
1662 
1663 	/* Check if requested first event is greater than actual. */
1664 	/* If so, adjust for it.  */
1665 	if (hba_event->last_id > first) {
1666 		/* Adjust entry index to first requested message */
1667 		index += (hba_event->last_id - first);
1668 		if (index >= log->size) {
1669 			index -= log->size;
1670 		}
1671 
1672 		first = hba_event->last_id;
1673 	}
1674 
1675 	/* Get the total number of new messages */
1676 	count = last - first;
1677 
1678 	/* Scan log for next event */
1679 	events = 0;
1680 	while (count-- && (events < max_events)) {
1681 		if (++index >= log->size) {
1682 			index = 0;
1683 		}
1684 
1685 		entry = &log->entry[index];
1686 
1687 		if (!entry->msg) {
1688 			break;
1689 		}
1690 
1691 		if ((entry->msg->level == EMLXS_EVENT) &&
1692 		    (entry->msg->mask & (EVT_LINK | EVT_RSCN))) {
1693 			/* Process this event */
1694 			switch (entry->msg->mask) {
1695 			case EVT_LINK:
1696 				byte = (uint8_t *)entry->bp;
1697 				linkspeed = byte[0];
1698 				liptype = byte[1];
1699 				linkinfo = (dfc_linkinfo_t *)&byte[4];
1700 
1701 				if (linkinfo->a_linkState == LNK_DOWN) {
1702 					eventinfo->EventCode =
1703 					    HBA_EVENT_LINK_DOWN;
1704 					eventinfo->Event.Link_EventInfo.
1705 					    PortFcId = linkinfo->a_DID;
1706 					eventinfo->Event.Link_EventInfo.
1707 					    Reserved[0] = 0;
1708 					eventinfo->Event.Link_EventInfo.
1709 					    Reserved[1] = 0;
1710 					eventinfo->Event.Link_EventInfo.
1711 					    Reserved[2] = 0;
1712 				} else {
1713 					eventinfo->EventCode =
1714 					    HBA_EVENT_LINK_UP;
1715 					eventinfo->Event.Link_EventInfo.
1716 					    PortFcId = linkinfo->a_DID;
1717 
1718 					if ((linkinfo->a_topology ==
1719 					    LNK_PUBLIC_LOOP) ||
1720 					    (linkinfo->a_topology ==
1721 					    LNK_LOOP)) {
1722 						eventinfo->Event.
1723 						    Link_EventInfo.
1724 						    Reserved[0] = 2;
1725 					} else {
1726 						eventinfo->Event.
1727 						    Link_EventInfo.
1728 						    Reserved[0] = 1;
1729 					}
1730 
1731 					eventinfo->Event.Link_EventInfo.
1732 					    Reserved[1] = liptype;
1733 					eventinfo->Event.Link_EventInfo.
1734 					    Reserved[2] = linkspeed;
1735 				}
1736 
1737 				break;
1738 
1739 			case EVT_RSCN:
1740 				word = (uint32_t *)entry->bp;
1741 				eventinfo->EventCode = HBA_EVENT_RSCN;
1742 				eventinfo->Event.RSCN_EventInfo.PortFcId =
1743 				    word[0] & 0xFFFFFF;
1744 				/* word[1] is the RSCN payload command */
1745 
1746 				aid = (fc_affected_id_t *)&word[2];
1747 
1748 				switch (aid->aff_format) {
1749 				case 0:	/* Port */
1750 					eventinfo->Event.RSCN_EventInfo.
1751 					    NPortPage =
1752 					    aid->aff_d_id & 0x00ffffff;
1753 					break;
1754 
1755 				case 1:	/* Area */
1756 					eventinfo->Event.RSCN_EventInfo.
1757 					    NPortPage =
1758 					    aid->aff_d_id & 0x00ffff00;
1759 					break;
1760 
1761 				case 2:	/* Domain */
1762 					eventinfo->Event.RSCN_EventInfo.
1763 					    NPortPage =
1764 					    aid->aff_d_id & 0x00ff0000;
1765 					break;
1766 
1767 				case 3:	/* Network */
1768 					eventinfo->Event.RSCN_EventInfo.
1769 					    NPortPage = 0;
1770 					break;
1771 				}
1772 
1773 				eventinfo->Event.RSCN_EventInfo.Reserved[0] =
1774 				    0;
1775 				eventinfo->Event.RSCN_EventInfo.Reserved[1] =
1776 				    0;
1777 
1778 				break;
1779 			}
1780 
1781 			eventinfo++;
1782 			events++;
1783 		}
1784 
1785 		hba_event->last_id = entry->id;
1786 	}
1787 
1788 	/* Adjust new count */
1789 	if (!count || (events >= hba_event->new)) {
1790 		hba_event->new = 0;
1791 	} else {
1792 		hba_event->new -= events;
1793 	}
1794 
1795 	/* Return number of events acquired */
1796 	*eventcount = events;
1797 
1798 	mutex_exit(&log->lock);
1799 
1800 	return (0);
1801 
1802 }  /* emlxs_get_dfc_eventinfo() */
1803 
1804 
1805 uint32_t
1806 emlxs_get_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event,
1807     uint32_t sleep)
1808 {
1809 	emlxs_hba_t *hba = HBA;
1810 	emlxs_msg_log_t *log;
1811 	uint32_t first;
1812 	uint32_t last;
1813 	uint32_t count;
1814 	uint32_t index;
1815 	uint32_t mask;
1816 	uint32_t i;
1817 	emlxs_msg_entry_t *entry;
1818 	uint32_t size;
1819 	uint32_t rc;
1820 
1821 	size = 0;
1822 
1823 	if (dfc_event->dataout && dfc_event->size) {
1824 		size = dfc_event->size;
1825 	}
1826 	dfc_event->size = 0;
1827 
1828 	/* Get the log file pointer */
1829 	log = &LOG;
1830 
1831 	/* Calculate the event index */
1832 	mask = dfc_event->event;
1833 	for (i = 0; i < 32; i++) {
1834 		if (mask & 0x01) {
1835 			break;
1836 		}
1837 
1838 		mask >>= 1;
1839 	}
1840 	if (i == 32) {
1841 		return (DFC_ARG_INVALID);
1842 	}
1843 
1844 	mutex_enter(&log->lock);
1845 
1846 	/* Check if log is empty */
1847 	if (log->count == 0) {
1848 		/* Make sure everything is initialized */
1849 		log->event_id[i] = 0;
1850 		dfc_event->last_id = 0;
1851 	} else {
1852 		/* Check ranges for safety */
1853 		if (log->event_id[i] > (log->count - 1)) {
1854 			log->event_id[i] = log->count - 1;
1855 		}
1856 
1857 		if (dfc_event->last_id > log->event_id[i]) {
1858 			dfc_event->last_id = log->event_id[i];
1859 		}
1860 	}
1861 
1862 wait_for_event:
1863 
1864 	/* Check if no new event has ocurred */
1865 	if (dfc_event->last_id == log->event_id[i]) {
1866 		if (!sleep) {
1867 			mutex_exit(&log->lock);
1868 			return (0);
1869 		}
1870 
1871 		/* While event is still active and */
1872 		/* no new event has been logged */
1873 		while ((dfc_event->event & hba->log_events) &&
1874 		    (dfc_event->last_id == log->event_id[i])) {
1875 			rc = cv_wait_sig(&log->lock_cv, &log->lock);
1876 
1877 			/* Check if thread was killed by kernel */
1878 			if (rc == 0) {
1879 				dfc_event->pid = 0;
1880 				dfc_event->event = 0;
1881 				mutex_exit(&log->lock);
1882 				return (0);
1883 			}
1884 		}
1885 
1886 		/* If the event is no longer registered then */
1887 		/* return immediately */
1888 		if (!(dfc_event->event & hba->log_events)) {
1889 			mutex_exit(&log->lock);
1890 			return (0);
1891 		}
1892 	}
1893 
1894 	/* !!! An event has occurred since last_id !!! */
1895 
1896 	/* Check if event data is not being requested */
1897 	if (!size) {
1898 		/* If so, then just return the last event id */
1899 		dfc_event->last_id = log->event_id[i];
1900 
1901 		mutex_exit(&log->lock);
1902 		return (0);
1903 	}
1904 
1905 	/* !!! The requester wants the next event buffer !!! */
1906 
1907 	/* Calculate the current buffer boundaries */
1908 
1909 	/* Get last entry id saved */
1910 	last = log->count - 1;
1911 
1912 	/* Get oldest entry id and its index */
1913 	/* Check if buffer has already been filled once */
1914 	if (log->count >= log->size) {
1915 		first = log->count - log->size;
1916 		index = log->next;
1917 	} else {	/* Buffer not yet filled */
1918 
1919 		first = 0;
1920 		index = 0;
1921 	}
1922 
1923 	/* Check to see if the buffer has wrapped since the last event */
1924 	if (first > log->event_id[i]) {
1925 		/* Update last_id to the last known event */
1926 		dfc_event->last_id = log->event_id[i];
1927 
1928 		/* Try waiting again if we can */
1929 		goto wait_for_event;
1930 	}
1931 
1932 	/* Check if requested first event is greater than actual. */
1933 	/* If so, adjust for it.  */
1934 	if (dfc_event->last_id > first) {
1935 		/* Adjust entry index to first requested message */
1936 		index += (dfc_event->last_id - first);
1937 		if (index >= log->size) {
1938 			index -= log->size;
1939 		}
1940 
1941 		first = dfc_event->last_id;
1942 	}
1943 
1944 	/* Get the total number of new messages */
1945 	count = last - first + 1;
1946 
1947 	/* Scan log for next event */
1948 	while (count--) {
1949 		if (++index >= log->size) {
1950 			index = 0;
1951 		}
1952 
1953 		entry = &log->entry[index];
1954 
1955 		if ((entry->msg->level == EMLXS_EVENT) &&
1956 		    (entry->msg->mask == dfc_event->event)) {
1957 			break;
1958 		}
1959 	}
1960 
1961 	/* Check if no new event was found in the current log buffer */
1962 	/* This would indicate that the buffer wrapped since that last event */
1963 	if (!count) {
1964 		/* Update last_id to the last known event */
1965 		dfc_event->last_id = log->event_id[i];
1966 
1967 		/* Try waiting again if we can */
1968 		goto wait_for_event;
1969 	}
1970 
1971 	/* !!! Next event found !!! */
1972 
1973 	/* Copy the context buffer to the buffer provided */
1974 	if (entry->bp && entry->size) {
1975 		if (entry->size < size) {
1976 			size = entry->size;
1977 		}
1978 
1979 		if (ddi_copyout((void *)entry->bp, dfc_event->dataout, size,
1980 		    dfc_event->mode) != 0) {
1981 			mutex_exit(&log->lock);
1982 
1983 			return (DFC_COPYOUT_ERROR);
1984 		}
1985 
1986 		/* Data has been retrieved by the apps */
1987 		entry->flag |= EMLX_EVENT_DONE;
1988 
1989 		dfc_event->size = size;
1990 	}
1991 
1992 	dfc_event->last_id = entry->id;
1993 
1994 	mutex_exit(&log->lock);
1995 	return (0);
1996 
1997 }  /* emlxs_get_dfc_event() */
1998 
1999 
2000 uint32_t
2001 emlxs_kill_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event)
2002 {
2003 	emlxs_hba_t *hba = HBA;
2004 	emlxs_msg_log_t *log;
2005 
2006 	/* Get the log file pointer */
2007 	log = &LOG;
2008 
2009 	mutex_enter(&log->lock);
2010 	dfc_event->pid = 0;
2011 	dfc_event->event = 0;
2012 	cv_broadcast(&log->lock_cv);
2013 	mutex_exit(&log->lock);
2014 
2015 	return (0);
2016 
2017 }  /* emlxs_kill_dfc_event() */
2018 
2019 
2020 #ifdef SAN_DIAG_SUPPORT
2021 uint32_t
2022 emlxs_get_sd_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event,
2023     uint32_t sleep)
2024 {
2025 	emlxs_hba_t		*hba = HBA;
2026 	emlxs_msg_log_t		*log;
2027 	emlxs_msg_entry_t	*entry;
2028 	uint32_t		size;
2029 	uint32_t		rc;
2030 	uint32_t		first;
2031 	uint32_t		last;
2032 	uint32_t		count;
2033 	uint32_t		index;
2034 	uint32_t		mask;
2035 	uint32_t		i;
2036 
2037 	size = 0;
2038 
2039 	if (dfc_event->dataout && dfc_event->size) {
2040 		size = dfc_event->size;
2041 	}
2042 	dfc_event->size = 0;
2043 
2044 	/* Get the log file pointer */
2045 	log = &LOG;
2046 
2047 	/* Calculate the event index */
2048 	mask = dfc_event->event;
2049 	for (i = 0; i < 32; i++) {
2050 		if (mask & 0x01)
2051 			break;
2052 
2053 		mask >>= 1;
2054 	}
2055 	if (i == 32)
2056 		return (DFC_ARG_INVALID);
2057 
2058 	mutex_enter(&log->lock);
2059 
2060 	/* Check if log is empty */
2061 	if (log->count == 0) {
2062 		/* Make sure everything is initialized */
2063 		log->event_id[i] = 0;
2064 		dfc_event->last_id = 0;
2065 	} else {
2066 		/* Check ranges for safety */
2067 		if (log->event_id[i] > (log->count - 1))
2068 			log->event_id[i] = log->count - 1;
2069 
2070 		if (dfc_event->last_id > log->event_id[i])
2071 			dfc_event->last_id = log->event_id[i];
2072 	}
2073 
2074 wait_for_sd_event:
2075 	/* Check if no new event has ocurred */
2076 	if (dfc_event->last_id == log->event_id[i]) {
2077 		if (!sleep) {
2078 			mutex_exit(&log->lock);
2079 			return (0);
2080 		}
2081 
2082 		/* While event is active and no new event has been logged */
2083 		while ((dfc_event->event & port->sd_reg_events) &&
2084 		    (dfc_event->last_id == log->event_id[i])) {
2085 			rc = cv_wait_sig(&log->lock_cv, &log->lock);
2086 
2087 			/* Check if thread was killed by kernel */
2088 			if (rc == 0) {
2089 				dfc_event->pid = 0;
2090 				dfc_event->event = 0;
2091 				mutex_exit(&log->lock);
2092 				return (0);
2093 			}
2094 		}
2095 
2096 		/* If the event is no longer registered then return */
2097 		if (!(dfc_event->event & port->sd_reg_events)) {
2098 			mutex_exit(&log->lock);
2099 			return (0);
2100 		}
2101 	}
2102 
2103 	/* !!! An event has occurred since last_id !!! */
2104 
2105 	/* Check if event data is not being requested */
2106 	if (!size) {
2107 		/* If so, then just return the last event id */
2108 		dfc_event->last_id = log->event_id[i];
2109 		mutex_exit(&log->lock);
2110 		return (0);
2111 	}
2112 
2113 	/* !!! The requester wants the next event buffer !!! */
2114 
2115 	/* Calculate the current buffer boundaries */
2116 
2117 	/* Get last entry id saved */
2118 	last = log->count - 1;
2119 
2120 	/* Get oldest entry id and its index */
2121 	/* Check if buffer has already been filled once */
2122 	if (log->count >= log->size) {
2123 		first = log->count - log->size;
2124 		index = log->next;
2125 	} else { /* Buffer not yet filled */
2126 		first = 0;
2127 		index = 0;
2128 	}
2129 
2130 	/* Check to see if the buffer has wrapped since the last event */
2131 	if (first > log->event_id[i]) {
2132 		/* Update last_id to the last known event */
2133 		dfc_event->last_id = log->event_id[i];
2134 
2135 		/* Try waiting again if we can */
2136 		goto wait_for_sd_event;
2137 	}
2138 
2139 	/* if requested first event is greater than actual, adjust for it. */
2140 	if (dfc_event->last_id > first) {
2141 		/* Adjust entry index to first requested message */
2142 		index += (dfc_event->last_id - first);
2143 		if (index >= log->size) {
2144 			index -= log->size;
2145 		}
2146 
2147 		first = dfc_event->last_id;
2148 	}
2149 
2150 	/* Get the total number of new messages */
2151 	count = last - first + 1;
2152 
2153 	/* Scan log for next event */
2154 	while (count--) {
2155 		if (++index >= log->size)
2156 			index = 0;
2157 
2158 		entry = &log->entry[index];
2159 
2160 		if ((entry->msg->level == EMLXS_EVENT) &&
2161 		    (entry->vpi == port->vpi) &&
2162 		    (entry->msg->mask == dfc_event->event))
2163 			break;
2164 	}
2165 
2166 	/* Check if no new event was found in the current log buffer */
2167 	/* This would indicate that the buffer wrapped since that last event */
2168 	if (!count) {
2169 		/* Update last_id to the last known event */
2170 		dfc_event->last_id = log->event_id[i];
2171 
2172 		/* Try waiting again if we can */
2173 		goto wait_for_sd_event;
2174 	}
2175 
2176 	/* !!! Next event found !!! */
2177 
2178 	/* Copy the context buffer to the buffer provided */
2179 	if (entry->bp && entry->size) {
2180 		if (entry->size < size)
2181 			size = entry->size;
2182 
2183 		if (ddi_copyout((void *) entry->bp, dfc_event->dataout,
2184 		    size, dfc_event->mode) != 0) {
2185 			mutex_exit(&log->lock);
2186 
2187 			return (DFC_COPYOUT_ERROR);
2188 		}
2189 
2190 		dfc_event->size = size;
2191 	}
2192 
2193 	dfc_event->last_id = entry->id;
2194 	mutex_exit(&log->lock);
2195 
2196 	return (0);
2197 } /* emlxs_get_sd_event */
2198 #endif /* SAN_DIAG_SUPPORT */
2199 
2200 
2201 #endif /* DFC_SUPPORT */
2202