1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at
9  * http://www.opensource.org/licenses/cddl1.txt.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #define	DEF_EVENT_STRUCT  /* Needed for emlxs_events.h in emlxs_event.h */
28 #include <emlxs.h>
29 
30 
31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
32 EMLXS_MSG_DEF(EMLXS_EVENT_C);
33 
34 
35 static uint32_t emlxs_event_check(emlxs_port_t *port, emlxs_event_t *evt);
36 static void emlxs_event_destroy(emlxs_hba_t *hba, emlxs_event_entry_t *entry);
37 
38 extern void
39 emlxs_null_func() {}
40 
41 
42 static uint32_t
43 emlxs_event_check(emlxs_port_t *port, emlxs_event_t *evt)
44 {
45 	emlxs_hba_t *hba = HBA;
46 
47 	/* Check if the event is being requested */
48 	if ((hba->event_mask & evt->mask)) {
49 		return (1);
50 	}
51 
52 #ifdef SAN_DIAG_SUPPORT
53 	if ((port->sd_event_mask & evt->mask)) {
54 		return (1);
55 	}
56 #endif /* SAN_DIAG_SUPPORT */
57 
58 	return (0);
59 
60 } /* emlxs_event_check() */
61 
62 
63 extern uint32_t
64 emlxs_event_queue_create(emlxs_hba_t *hba)
65 {
66 	emlxs_event_queue_t *eventq = &EVENTQ;
67 	ddi_iblock_cookie_t iblock;
68 
69 	/* Clear the queue */
70 	bzero(eventq, sizeof (emlxs_event_queue_t));
71 
72 	cv_init(&eventq->lock_cv, NULL, CV_DRIVER, NULL);
73 
74 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
75 		/* Get the current interrupt block cookie */
76 		(void) ddi_get_iblock_cookie(hba->dip, (uint_t)EMLXS_INUMBER,
77 		    &iblock);
78 
79 		/* Create the mutex lock */
80 		mutex_init(&eventq->lock, NULL, MUTEX_DRIVER, (void *)iblock);
81 	}
82 #ifdef  MSI_SUPPORT
83 	else {
84 		/* Create event mutex lock */
85 		mutex_init(&eventq->lock, NULL, MUTEX_DRIVER,
86 		    DDI_INTR_PRI(hba->intr_arg));
87 	}
88 #endif
89 
90 	return (1);
91 
92 } /* emlxs_event_queue_create() */
93 
94 
95 extern void
96 emlxs_event_queue_destroy(emlxs_hba_t *hba)
97 {
98 	emlxs_port_t *vport;
99 	emlxs_event_queue_t *eventq = &EVENTQ;
100 	uint32_t i;
101 	uint32_t wakeup = 0;
102 
103 	mutex_enter(&eventq->lock);
104 
105 	/* Clear all event masks and broadcast a wakeup */
106 	/* to clear any sleeping threads */
107 	if (hba->event_mask) {
108 		hba->event_mask = 0;
109 		hba->event_timer = 0;
110 		wakeup = 1;
111 	}
112 
113 	for (i = 0; i < MAX_VPORTS; i++) {
114 		vport = &VPORT(i);
115 
116 		if (vport->sd_event_mask) {
117 			vport->sd_event_mask = 0;
118 			wakeup = 1;
119 		}
120 	}
121 
122 	if (wakeup) {
123 		cv_broadcast(&eventq->lock_cv);
124 
125 		mutex_exit(&eventq->lock);
126 		BUSYWAIT_MS(10);
127 		mutex_enter(&eventq->lock);
128 	}
129 
130 	/* Destroy the remaining events */
131 	while (eventq->first) {
132 		emlxs_event_destroy(hba, eventq->first);
133 	}
134 
135 	mutex_exit(&eventq->lock);
136 
137 	/* Destroy the queue lock */
138 	mutex_destroy(&eventq->lock);
139 	cv_destroy(&eventq->lock_cv);
140 
141 	/* Clear the queue */
142 	bzero(eventq, sizeof (emlxs_event_queue_t));
143 
144 	return;
145 
146 } /* emlxs_event_queue_destroy() */
147 
148 
149 /* Event queue lock must be held */
150 static void
151 emlxs_event_destroy(emlxs_hba_t *hba, emlxs_event_entry_t *entry)
152 {
153 	emlxs_event_queue_t *eventq = &EVENTQ;
154 	emlxs_port_t *port;
155 	uint32_t missed = 0;
156 
157 	port = (emlxs_port_t *)entry->port;
158 
159 	eventq->count--;
160 	if (eventq->count == 0) {
161 		eventq->first = NULL;
162 		eventq->last = NULL;
163 	} else {
164 		if (entry->prev) {
165 			entry->prev->next = entry->next;
166 		}
167 		if (entry->next) {
168 			entry->next->prev = entry->prev;
169 		}
170 		if (eventq->first == entry) {
171 			eventq->first = entry->next;
172 		}
173 		if (eventq->last == entry) {
174 			eventq->last = entry->prev;
175 		}
176 	}
177 
178 	entry->prev = NULL;
179 	entry->next = NULL;
180 
181 	if ((entry->evt->mask == EVT_LINK) ||
182 	    (entry->evt->mask == EVT_RSCN)) {
183 		if (!(entry->flag & EMLXS_DFC_EVENT_DONE)) {
184 			hba->hba_event.missed++;
185 			missed = 1;
186 		}
187 	}
188 
189 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_dequeued_msg,
190 	    "%s[%d]: flag=%x missed=%d cnt=%d",
191 	    entry->evt->label, entry->id, entry->flag, missed, eventq->count);
192 
193 	/* Call notification handler */
194 	if (entry->evt->destroy != emlxs_null_func) {
195 		entry->evt->destroy(entry);
196 	}
197 
198 	/* Free context buffer */
199 	if (entry->bp && entry->size) {
200 		kmem_free(entry->bp, entry->size);
201 	}
202 
203 	/* Free entry buffer */
204 	kmem_free(entry, sizeof (emlxs_event_entry_t));
205 
206 	return;
207 
208 } /* emlxs_event_destroy() */
209 
210 
211 extern void
212 emlxs_event(emlxs_port_t *port, emlxs_event_t *evt, void *bp, uint32_t size)
213 {
214 	emlxs_hba_t *hba = HBA;
215 	emlxs_event_queue_t *eventq = &EVENTQ;
216 	emlxs_event_entry_t *entry;
217 	uint32_t i;
218 	uint32_t mask;
219 
220 	if (emlxs_event_check(port, evt) == 0) {
221 		goto failed;
222 	}
223 
224 	/* Create event entry */
225 	if (!(entry = (emlxs_event_entry_t *)kmem_alloc(
226 	    sizeof (emlxs_event_entry_t), KM_NOSLEEP))) {
227 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
228 		    "%s: Unable to allocate event entry.", evt->label);
229 
230 		goto failed;
231 	}
232 
233 	/* Initialize */
234 	bzero(entry, sizeof (emlxs_event_entry_t));
235 
236 	entry->evt = evt;
237 	entry->port = (void *)port;
238 	entry->bp = bp;
239 	entry->size = size;
240 
241 	mutex_enter(&eventq->lock);
242 
243 	/* Set the event timer */
244 	entry->timestamp = hba->timer_tics;
245 	if (evt->timeout) {
246 		entry->timer = entry->timestamp + evt->timeout;
247 	}
248 
249 	/* Eventq id starts with 1 */
250 	if (eventq->next_id == 0) {
251 		eventq->next_id = 1;
252 	}
253 
254 	/* Set the event id */
255 	entry->id = eventq->next_id++;
256 
257 	/* Set last event table */
258 	mask = evt->mask;
259 	for (i = 0; i < 32; i++) {
260 		if (mask & 0x01) {
261 			eventq->last_id[i] = entry->id;
262 		}
263 		mask >>= 1;
264 	}
265 
266 	/* Put event on bottom of queue */
267 	entry->next = NULL;
268 	if (eventq->count == 0) {
269 		entry->prev = NULL;
270 		eventq->first = entry;
271 		eventq->last = entry;
272 	} else {
273 		entry->prev = eventq->last;
274 		entry->prev->next = entry;
275 		eventq->last = entry;
276 	}
277 	eventq->count++;
278 
279 	if ((entry->evt->mask == EVT_LINK) ||
280 	    (entry->evt->mask == EVT_RSCN)) {
281 		hba->hba_event.new++;
282 	}
283 
284 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_queued_msg,
285 	    "%s[%d]: bp=%p size=%d cnt=%d", entry->evt->label,
286 	    entry->id, bp, size, eventq->count);
287 
288 	/* Broadcast the event */
289 	cv_broadcast(&eventq->lock_cv);
290 
291 	mutex_exit(&eventq->lock);
292 
293 	return;
294 
295 failed:
296 
297 	if (bp && size) {
298 		kmem_free(bp, size);
299 	}
300 
301 	return;
302 
303 } /* emlxs_event() */
304 
305 
306 extern void
307 emlxs_timer_check_events(emlxs_hba_t *hba)
308 {
309 	emlxs_config_t *cfg = &CFG;
310 	emlxs_event_queue_t *eventq = &EVENTQ;
311 	emlxs_event_entry_t *entry;
312 	emlxs_event_entry_t *next;
313 
314 	if (!cfg[CFG_TIMEOUT_ENABLE].current) {
315 		return;
316 	}
317 
318 	if ((hba->event_timer > hba->timer_tics)) {
319 		return;
320 	}
321 
322 	if (eventq->count) {
323 		mutex_enter(&eventq->lock);
324 
325 		entry = eventq->first;
326 		while (entry) {
327 			if ((!entry->timer) ||
328 			    (entry->timer > hba->timer_tics)) {
329 				entry = entry->next;
330 				continue;
331 			}
332 
333 			/* Event timed out, destroy it */
334 			next = entry->next;
335 			emlxs_event_destroy(hba, entry);
336 			entry = next;
337 		}
338 
339 		mutex_exit(&eventq->lock);
340 	}
341 
342 	/* Set next event timer check */
343 	hba->event_timer = hba->timer_tics + EMLXS_EVENT_PERIOD;
344 
345 	return;
346 
347 } /* emlxs_timer_check_events() */
348 
349 
350 extern void
351 emlxs_log_rscn_event(emlxs_port_t *port, uint8_t *payload, uint32_t size)
352 {
353 	uint8_t *bp;
354 	uint32_t *ptr;
355 
356 	/* Check if the event is being requested */
357 	if (emlxs_event_check(port, &emlxs_rscn_event) == 0) {
358 		return;
359 	}
360 
361 	if (size > MAX_RSCN_PAYLOAD) {
362 		size = MAX_RSCN_PAYLOAD;
363 	}
364 
365 	size += sizeof (uint32_t);
366 
367 	/* Save a copy of the payload for the event log */
368 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
369 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
370 		    "%s: Unable to allocate buffer.", emlxs_rscn_event.label);
371 
372 		return;
373 	}
374 
375 	/*
376 	 * Buffer Format:
377 	 *	word[0] = DID of the RSCN
378 	 *	word[1] = RSCN Payload
379 	 */
380 	ptr = (uint32_t *)bp;
381 	*ptr++ = port->did;
382 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
383 
384 	emlxs_event(port, &emlxs_rscn_event, bp, size);
385 
386 	return;
387 
388 } /* emlxs_log_rscn_event() */
389 
390 
391 extern void
392 emlxs_log_vportrscn_event(emlxs_port_t *port, uint8_t *payload, uint32_t size)
393 {
394 	uint8_t *bp;
395 	uint8_t *ptr;
396 
397 	/* Check if the event is being requested */
398 	if (emlxs_event_check(port, &emlxs_vportrscn_event) == 0) {
399 		return;
400 	}
401 
402 	if (size > MAX_RSCN_PAYLOAD) {
403 		size = MAX_RSCN_PAYLOAD;
404 	}
405 
406 	size += sizeof (NAME_TYPE);
407 
408 	/* Save a copy of the payload for the event log */
409 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
410 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
411 		    "%s: Unable to allocate buffer.",
412 		    emlxs_vportrscn_event.label);
413 
414 		return;
415 	}
416 
417 	/*
418 	 * Buffer Format:
419 	 *	word[0 - 4] = WWPN of the RSCN
420 	 *	word[5] = RSCN Payload
421 	 */
422 	ptr = bp;
423 	bcopy(&port->wwpn, ptr, sizeof (NAME_TYPE));
424 	ptr += sizeof (NAME_TYPE);
425 	bcopy(payload, ptr, (size - sizeof (NAME_TYPE)));
426 
427 	emlxs_event(port, &emlxs_vportrscn_event, bp, size);
428 
429 	return;
430 
431 } /* emlxs_log_vportrscn_event() */
432 
433 
434 extern uint32_t
435 emlxs_flush_ct_event(emlxs_port_t *port, uint32_t rxid)
436 {
437 	emlxs_hba_t *hba = HBA;
438 	emlxs_event_queue_t *eventq = &EVENTQ;
439 	emlxs_event_entry_t *entry;
440 	uint32_t *ptr;
441 	uint32_t found = 0;
442 
443 	mutex_enter(&eventq->lock);
444 
445 	for (entry = eventq->first; entry != NULL; entry = entry->next) {
446 		if ((entry->port != port) ||
447 		    (entry->evt != &emlxs_ct_event)) {
448 			continue;
449 		}
450 
451 		ptr = (uint32_t *)entry->bp;
452 		if (rxid == *ptr) {
453 			/* This will prevent a CT exchange abort */
454 			/* in emlxs_ct_event_destroy() */
455 			entry->flag |= EMLXS_DFC_EVENT_DONE;
456 
457 			emlxs_event_destroy(hba, entry);
458 			found = 1;
459 			break;
460 		}
461 	}
462 
463 	mutex_exit(&eventq->lock);
464 
465 	return (found);
466 
467 } /* emlxs_flush_ct_event() */
468 
469 
470 extern uint32_t
471 emlxs_log_ct_event(emlxs_port_t *port, uint8_t *payload, uint32_t size,
472     uint32_t rxid)
473 {
474 	uint8_t *bp;
475 	uint32_t *ptr;
476 
477 	/* Check if the event is being requested */
478 	if (emlxs_event_check(port, &emlxs_ct_event) == 0) {
479 		return (1);
480 	}
481 
482 	if (size > MAX_CT_PAYLOAD) {
483 		size = MAX_CT_PAYLOAD;
484 	}
485 
486 	size += sizeof (uint32_t);
487 
488 	/* Save a copy of the payload for the event log */
489 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
490 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
491 		    "%s: Unable to allocate buffer.", emlxs_ct_event.label);
492 
493 		return (1);
494 	}
495 
496 	/*
497 	 * Buffer Format:
498 	 *	word[0] = RXID tag for outgoing reply to this CT request
499 	 *	word[1] = CT Payload
500 	 */
501 	ptr = (uint32_t *)bp;
502 	*ptr++ = rxid;
503 	bcopy(payload, (char *)ptr, (size - sizeof (uint32_t)));
504 
505 	emlxs_event(port, &emlxs_ct_event, bp, size);
506 
507 	return (0);
508 
509 } /* emlxs_log_ct_event() */
510 
511 
512 extern void
513 emlxs_ct_event_destroy(emlxs_event_entry_t *entry)
514 {
515 	emlxs_port_t *port = (emlxs_port_t *)entry->port;
516 	emlxs_hba_t *hba = HBA;
517 	uint32_t rxid;
518 
519 	if (!(entry->flag & EMLXS_DFC_EVENT_DONE)) {
520 
521 		rxid = *(uint32_t *)entry->bp;
522 
523 		/* Abort exchange */
524 		emlxs_thread_spawn(hba, emlxs_abort_ct_exchange,
525 		    entry->port, (void *)(unsigned long)rxid);
526 	}
527 
528 	return;
529 
530 } /* emlxs_ct_event_destroy() */
531 
532 
533 extern void
534 emlxs_log_link_event(emlxs_port_t *port)
535 {
536 	emlxs_hba_t *hba = HBA;
537 	uint8_t *bp;
538 	dfc_linkinfo_t *linkinfo;
539 	uint8_t *byte;
540 	uint8_t *linkspeed;
541 	uint8_t *liptype;
542 	uint8_t *resv1;
543 	uint8_t *resv2;
544 	uint32_t size;
545 
546 	/* Check if the event is being requested */
547 	if (emlxs_event_check(port, &emlxs_link_event) == 0) {
548 		return;
549 	}
550 
551 	size = sizeof (dfc_linkinfo_t) + sizeof (uint32_t);
552 
553 	/* Save a copy of the buffer for the event log */
554 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
555 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
556 		    "%s: Unable to allocate buffer.", emlxs_link_event.label);
557 
558 		return;
559 	}
560 
561 	/*
562 	 * Buffer Format:
563 	 *	word[0] = Linkspeed:8
564 	 *	word[0] = LIP_type:8
565 	 *	word[0] = resv1:8
566 	 *	word[0] = resv2:8
567 	 *	word[1] = dfc_linkinfo_t data
568 	 */
569 	byte = (uint8_t *)bp;
570 	linkspeed = &byte[0];
571 	liptype = &byte[1];
572 	resv1 = &byte[2];
573 	resv2 = &byte[3];
574 	linkinfo = (dfc_linkinfo_t *)&byte[4];
575 
576 	*resv1 = 0;
577 	*resv2 = 0;
578 
579 	if (hba->state <= FC_LINK_DOWN) {
580 		*linkspeed = 0;
581 		*liptype = 0;
582 	} else {
583 		/* Set linkspeed */
584 		if (hba->linkspeed == LA_2GHZ_LINK) {
585 			*linkspeed = HBA_PORTSPEED_2GBIT;
586 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
587 			*linkspeed = HBA_PORTSPEED_4GBIT;
588 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
589 			*linkspeed = HBA_PORTSPEED_8GBIT;
590 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
591 			*linkspeed = HBA_PORTSPEED_10GBIT;
592 		} else if (hba->linkspeed == LA_16GHZ_LINK) {
593 			*linkspeed = HBA_PORTSPEED_16GBIT;
594 		} else {
595 			*linkspeed = HBA_PORTSPEED_1GBIT;
596 		}
597 
598 		/* Set LIP type */
599 		*liptype = port->lip_type;
600 	}
601 
602 	bzero(linkinfo, sizeof (dfc_linkinfo_t));
603 
604 	linkinfo->a_linkEventTag = hba->link_event_tag;
605 	linkinfo->a_linkUp = HBASTATS.LinkUp;
606 	linkinfo->a_linkDown = HBASTATS.LinkDown;
607 	linkinfo->a_linkMulti = HBASTATS.LinkMultiEvent;
608 
609 	if (hba->state <= FC_LINK_DOWN) {
610 		linkinfo->a_linkState = LNK_DOWN;
611 		linkinfo->a_DID = port->prev_did;
612 	} else if (hba->state < FC_READY) {
613 		linkinfo->a_linkState = LNK_DISCOVERY;
614 	} else {
615 		linkinfo->a_linkState = LNK_READY;
616 	}
617 
618 	if (linkinfo->a_linkState != LNK_DOWN) {
619 		if (hba->topology == TOPOLOGY_LOOP) {
620 			if (hba->flag & FC_FABRIC_ATTACHED) {
621 				linkinfo->a_topology = LNK_PUBLIC_LOOP;
622 			} else {
623 				linkinfo->a_topology = LNK_LOOP;
624 			}
625 
626 			linkinfo->a_alpa = port->did & 0xff;
627 			linkinfo->a_DID = linkinfo->a_alpa;
628 			linkinfo->a_alpaCnt = port->alpa_map[0];
629 
630 			if (linkinfo->a_alpaCnt > 127) {
631 				linkinfo->a_alpaCnt = 127;
632 			}
633 
634 			bcopy((void *)&port->alpa_map[1], linkinfo->a_alpaMap,
635 			    linkinfo->a_alpaCnt);
636 		} else {
637 			if (port->node_count == 1) {
638 				linkinfo->a_topology = LNK_PT2PT;
639 			} else {
640 				linkinfo->a_topology = LNK_FABRIC;
641 			}
642 
643 			linkinfo->a_DID = port->did;
644 		}
645 	}
646 
647 	bcopy(&hba->wwpn, linkinfo->a_wwpName, 8);
648 	bcopy(&hba->wwnn, linkinfo->a_wwnName, 8);
649 
650 	emlxs_event(port, &emlxs_link_event, bp, size);
651 
652 	return;
653 
654 } /* emlxs_log_link_event() */
655 
656 
657 extern void
658 emlxs_log_dump_event(emlxs_port_t *port, uint8_t *buffer, uint32_t size)
659 {
660 	emlxs_hba_t *hba = HBA;
661 	uint8_t *bp;
662 
663 	/* Check if the event is being requested */
664 	if (emlxs_event_check(port, &emlxs_dump_event) == 0) {
665 #ifdef DUMP_SUPPORT
666 		/* Schedule a dump thread */
667 		emlxs_dump(hba, EMLXS_DRV_DUMP, 0, 0);
668 #endif /* DUMP_SUPPORT */
669 		return;
670 	}
671 
672 	if (buffer && size) {
673 		/* Save a copy of the buffer for the event log */
674 		if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
675 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
676 			    "%s: Unable to allocate buffer.",
677 			    emlxs_dump_event.label);
678 
679 			return;
680 		}
681 
682 		bcopy(buffer, bp, size);
683 	} else {
684 		bp = NULL;
685 		size = 0;
686 	}
687 
688 	emlxs_event(port, &emlxs_dump_event, bp, size);
689 
690 	return;
691 
692 } /* emlxs_log_dump_event() */
693 
694 
695 extern void
696 emlxs_log_temp_event(emlxs_port_t *port, uint32_t type, uint32_t temp)
697 {
698 	emlxs_hba_t *hba = HBA;
699 	uint32_t *bp;
700 	uint32_t size;
701 
702 	/* Check if the event is being requested */
703 	if (emlxs_event_check(port, &emlxs_temp_event) == 0) {
704 #ifdef DUMP_SUPPORT
705 		/* Schedule a dump thread */
706 		emlxs_dump(hba, EMLXS_TEMP_DUMP, type, temp);
707 #endif /* DUMP_SUPPORT */
708 		return;
709 	}
710 
711 	size = 2 * sizeof (uint32_t);
712 
713 	if (!(bp = (uint32_t *)kmem_alloc(size, KM_NOSLEEP))) {
714 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
715 		    "%s: Unable to allocate buffer.", emlxs_temp_event.label);
716 
717 		return;
718 	}
719 
720 	bp[0] = type;
721 	bp[1] = temp;
722 
723 	emlxs_event(port, &emlxs_temp_event, bp, size);
724 
725 	return;
726 
727 } /* emlxs_log_temp_event() */
728 
729 
730 
731 extern void
732 emlxs_log_fcoe_event(emlxs_port_t *port, menlo_init_rsp_t *init_rsp)
733 {
734 	emlxs_hba_t *hba = HBA;
735 	uint8_t *bp;
736 	uint32_t size;
737 
738 	/* Check if the event is being requested */
739 	if (emlxs_event_check(port, &emlxs_fcoe_event) == 0) {
740 		return;
741 	}
742 
743 	/* Check if this is a FCOE adapter */
744 	if (hba->model_info.device_id != PCI_DEVICE_ID_HORNET) {
745 		return;
746 	}
747 
748 	size = sizeof (menlo_init_rsp_t);
749 
750 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
751 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
752 		    "%s: Unable to allocate buffer.", emlxs_fcoe_event.label);
753 
754 		return;
755 	}
756 
757 	bcopy((uint8_t *)init_rsp, bp, size);
758 
759 	emlxs_event(port, &emlxs_fcoe_event, bp, size);
760 
761 	return;
762 
763 } /* emlxs_log_fcoe_event() */
764 
765 
766 extern void
767 emlxs_log_async_event(emlxs_port_t *port, IOCB *iocb)
768 {
769 	uint8_t *bp;
770 	uint32_t size;
771 
772 	if (emlxs_event_check(port, &emlxs_async_event) == 0) {
773 		return;
774 	}
775 
776 	/* ASYNC_STATUS_CN response size */
777 	size = 64;
778 
779 	if (!(bp = (uint8_t *)kmem_alloc(size, KM_NOSLEEP))) {
780 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
781 		    "%s: Unable to allocate buffer.", emlxs_async_event.label);
782 
783 		return;
784 	}
785 
786 	bcopy((uint8_t *)iocb, bp, size);
787 
788 	emlxs_event(port, &emlxs_async_event, bp, size);
789 
790 	return;
791 
792 } /* emlxs_log_async_event() */
793 
794 
795 extern uint32_t
796 emlxs_get_dfc_eventinfo(emlxs_port_t *port, HBA_EVENTINFO *eventinfo,
797     uint32_t *eventcount, uint32_t *missed)
798 {
799 	emlxs_hba_t *hba = HBA;
800 	emlxs_event_queue_t *eventq = &EVENTQ;
801 	emlxs_event_entry_t *entry;
802 	uint32_t max_events;
803 	dfc_linkinfo_t *linkinfo;
804 	uint32_t *word;
805 	uint8_t *byte;
806 	uint8_t linkspeed;
807 	uint8_t liptype;
808 	fc_affected_id_t *aid;
809 	uint32_t events;
810 	uint8_t format;
811 
812 	if (!eventinfo || !eventcount || !missed) {
813 		return (DFC_ARG_NULL);
814 	}
815 
816 	max_events = *eventcount;
817 	*eventcount = 0;
818 	*missed = 0;
819 
820 	mutex_enter(&eventq->lock);
821 
822 	/* Account for missed events */
823 	if (hba->hba_event.new > hba->hba_event.missed) {
824 		hba->hba_event.new -= hba->hba_event.missed;
825 	} else {
826 		hba->hba_event.new = 0;
827 	}
828 
829 	*missed = hba->hba_event.missed;
830 	hba->hba_event.missed = 0;
831 
832 	if (!hba->hba_event.new) {
833 		hba->hba_event.last_id = eventq->next_id - 1;
834 		mutex_exit(&eventq->lock);
835 		return (0);
836 	}
837 
838 	/* A new event has occurred since last acquisition */
839 
840 	events = 0;
841 	entry = eventq->first;
842 	while (entry && (events < max_events)) {
843 
844 		/* Skip old events */
845 		if (entry->id <= hba->hba_event.last_id) {
846 			entry = entry->next;
847 			continue;
848 		}
849 
850 		/* Process this entry */
851 		switch (entry->evt->mask) {
852 		case EVT_LINK:
853 			byte = (uint8_t *)entry->bp;
854 			linkspeed = byte[0];
855 			liptype = byte[1];
856 			linkinfo = (dfc_linkinfo_t *)&byte[4];
857 
858 			if (linkinfo->a_linkState == LNK_DOWN) {
859 				eventinfo->EventCode =
860 				    HBA_EVENT_LINK_DOWN;
861 				eventinfo->Event.Link_EventInfo.
862 				    PortFcId = linkinfo->a_DID;
863 				eventinfo->Event.Link_EventInfo.
864 				    Reserved[0] = 0;
865 				eventinfo->Event.Link_EventInfo.
866 				    Reserved[1] = 0;
867 				eventinfo->Event.Link_EventInfo.
868 				    Reserved[2] = 0;
869 			} else {
870 				eventinfo->EventCode =
871 				    HBA_EVENT_LINK_UP;
872 				eventinfo->Event.Link_EventInfo.
873 				    PortFcId = linkinfo->a_DID;
874 
875 				if ((linkinfo->a_topology ==
876 				    LNK_PUBLIC_LOOP) ||
877 				    (linkinfo->a_topology ==
878 				    LNK_LOOP)) {
879 					eventinfo->Event.
880 					    Link_EventInfo.
881 					    Reserved[0] = 2;
882 				} else {
883 					eventinfo->Event.
884 					    Link_EventInfo.
885 					    Reserved[0] = 1;
886 				}
887 
888 				eventinfo->Event.Link_EventInfo.
889 				    Reserved[1] = liptype;
890 				eventinfo->Event.Link_EventInfo.
891 				    Reserved[2] = linkspeed;
892 			}
893 
894 			eventinfo++;
895 			events++;
896 			hba->hba_event.new--;
897 			break;
898 
899 		case EVT_RSCN:
900 			word = (uint32_t *)entry->bp;
901 			eventinfo->EventCode = HBA_EVENT_RSCN;
902 			eventinfo->Event.RSCN_EventInfo.PortFcId =
903 			    word[0] & 0xFFFFFF;
904 			/* word[1] is the RSCN payload command */
905 
906 			aid = (fc_affected_id_t *)&word[2];
907 			format = aid->aff_format;
908 
909 			switch (format) {
910 			case 0:	/* Port */
911 				eventinfo->Event.RSCN_EventInfo.
912 				    NPortPage =
913 				    aid->aff_d_id & 0x00ffffff;
914 				break;
915 
916 			case 1:	/* Area */
917 				eventinfo->Event.RSCN_EventInfo.
918 				    NPortPage =
919 				    aid->aff_d_id & 0x00ffff00;
920 				break;
921 
922 			case 2:	/* Domain */
923 				eventinfo->Event.RSCN_EventInfo.
924 				    NPortPage =
925 				    aid->aff_d_id & 0x00ff0000;
926 				break;
927 
928 			case 3:	/* Network */
929 				eventinfo->Event.RSCN_EventInfo.
930 				    NPortPage = 0;
931 				break;
932 			}
933 
934 			eventinfo->Event.RSCN_EventInfo.Reserved[0] =
935 			    0;
936 			eventinfo->Event.RSCN_EventInfo.Reserved[1] =
937 			    0;
938 
939 			eventinfo++;
940 			events++;
941 			hba->hba_event.new--;
942 			break;
943 		}
944 
945 		hba->hba_event.last_id = entry->id;
946 		entry = entry->next;
947 	}
948 
949 	/* Return number of events acquired */
950 	*eventcount = events;
951 
952 	mutex_exit(&eventq->lock);
953 
954 	return (0);
955 
956 } /* emlxs_get_dfc_eventinfo() */
957 
958 
959 void
960 emlxs_get_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event,
961     uint32_t sleep)
962 {
963 	emlxs_hba_t *hba = HBA;
964 	emlxs_event_queue_t *eventq = &EVENTQ;
965 	emlxs_event_entry_t *entry;
966 	uint32_t found;
967 	uint32_t mask;
968 	uint32_t i;
969 	uint32_t size = 0;
970 	uint32_t rc;
971 
972 	if (dfc_event->dataout && dfc_event->size) {
973 		size = dfc_event->size;
974 	}
975 	dfc_event->size = 0;
976 
977 	/* Calculate the event index */
978 	mask = dfc_event->event;
979 	for (i = 0; i < 32; i++) {
980 		if (mask & 0x01) {
981 			break;
982 		}
983 
984 		mask >>= 1;
985 	}
986 
987 	if (i == 32) {
988 		return;
989 	}
990 
991 	mutex_enter(&eventq->lock);
992 
993 wait_for_event:
994 
995 	/* Check if no new event has occurred */
996 	if (dfc_event->last_id == eventq->last_id[i]) {
997 		if (!sleep) {
998 			mutex_exit(&eventq->lock);
999 			return;
1000 		}
1001 
1002 		/* While event is still active and */
1003 		/* no new event has been logged */
1004 		while ((dfc_event->event & hba->event_mask) &&
1005 		    (dfc_event->last_id == eventq->last_id[i])) {
1006 
1007 			rc = cv_wait_sig(&eventq->lock_cv, &eventq->lock);
1008 
1009 			/* Check if thread was killed by kernel */
1010 			if (rc == 0) {
1011 				dfc_event->pid = 0;
1012 				dfc_event->event = 0;
1013 				mutex_exit(&eventq->lock);
1014 				return;
1015 			}
1016 		}
1017 
1018 		/* If the event is no longer registered then */
1019 		/* return immediately */
1020 		if (!(dfc_event->event & hba->event_mask)) {
1021 			mutex_exit(&eventq->lock);
1022 			return;
1023 		}
1024 	}
1025 
1026 	/* !!! An event has occurred since last_id !!! */
1027 
1028 	/* Check if event data is not being requested */
1029 	if (!size) {
1030 		/* If so, then just return the last event id */
1031 		dfc_event->last_id = eventq->last_id[i];
1032 
1033 		mutex_exit(&eventq->lock);
1034 		return;
1035 	}
1036 
1037 	/* !!! The requester wants the next event buffer !!! */
1038 
1039 	found = 0;
1040 	entry = eventq->first;
1041 	while (entry) {
1042 		if ((entry->id > dfc_event->last_id) &&
1043 		    (entry->evt->mask == dfc_event->event)) {
1044 			found = 1;
1045 			break;
1046 		}
1047 
1048 		entry = entry->next;
1049 	}
1050 
1051 	if (!found) {
1052 		/* Update last_id to the last known event */
1053 		dfc_event->last_id = eventq->last_id[i];
1054 
1055 		/* Try waiting again if we can */
1056 		goto wait_for_event;
1057 	}
1058 
1059 	/* !!! Next event found !!! */
1060 
1061 	/* Copy the context buffer to the buffer provided */
1062 	if (entry->bp && entry->size) {
1063 		if (entry->size < size) {
1064 			size = entry->size;
1065 		}
1066 
1067 		bcopy((void *)entry->bp, dfc_event->dataout, size);
1068 
1069 		/* Event has been retrieved by DFCLIB */
1070 		entry->flag |= EMLXS_DFC_EVENT_DONE;
1071 
1072 		dfc_event->size = size;
1073 	}
1074 
1075 	dfc_event->last_id = entry->id;
1076 
1077 	mutex_exit(&eventq->lock);
1078 
1079 	return;
1080 
1081 } /* emlxs_get_dfc_event() */
1082 
1083 
1084 uint32_t
1085 emlxs_kill_dfc_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event)
1086 {
1087 	emlxs_hba_t *hba = HBA;
1088 	emlxs_event_queue_t *eventq = &EVENTQ;
1089 
1090 	mutex_enter(&eventq->lock);
1091 	dfc_event->pid = 0;
1092 	dfc_event->event = 0;
1093 	cv_broadcast(&eventq->lock_cv);
1094 	mutex_exit(&eventq->lock);
1095 
1096 	return (0);
1097 
1098 } /* emlxs_kill_dfc_event() */
1099 
1100 
1101 #ifdef SAN_DIAG_SUPPORT
1102 extern void
1103 emlxs_log_sd_basic_els_event(emlxs_port_t *port, uint32_t subcat,
1104     HBA_WWN *portname, HBA_WWN *nodename)
1105 {
1106 	struct sd_plogi_rcv_v0	*bp;
1107 	uint32_t		size;
1108 
1109 	/* Check if the event is being requested */
1110 	if (emlxs_event_check(port, &emlxs_sd_els_event) == 0) {
1111 		return;
1112 	}
1113 
1114 	size = sizeof (struct sd_plogi_rcv_v0);
1115 
1116 	if (!(bp = (struct sd_plogi_rcv_v0 *)kmem_alloc(size, KM_NOSLEEP))) {
1117 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1118 		    "%s: Unable to allocate buffer.", emlxs_sd_els_event.label);
1119 
1120 		return;
1121 	}
1122 
1123 	/*
1124 	 * we are using version field to store subtype, libdfc
1125 	 * will fix this up before returning data to app.
1126 	 */
1127 	bp->sd_plogir_version = subcat;
1128 	bcopy((uint8_t *)portname, (uint8_t *)&bp->sd_plogir_portname,
1129 	    sizeof (HBA_WWN));
1130 	bcopy((uint8_t *)nodename, (uint8_t *)&bp->sd_plogir_nodename,
1131 	    sizeof (HBA_WWN));
1132 
1133 	emlxs_event(port, &emlxs_sd_els_event, bp, size);
1134 
1135 	return;
1136 
1137 } /* emlxs_log_sd_basic_els_event() */
1138 
1139 
1140 extern void
1141 emlxs_log_sd_prlo_event(emlxs_port_t *port, HBA_WWN *remoteport)
1142 {
1143 	struct sd_prlo_rcv_v0	*bp;
1144 	uint32_t		size;
1145 
1146 	/* Check if the event is being requested */
1147 	if (emlxs_event_check(port, &emlxs_sd_els_event) == 0) {
1148 		return;
1149 	}
1150 
1151 	size = sizeof (struct sd_prlo_rcv_v0);
1152 
1153 	if (!(bp = (struct sd_prlo_rcv_v0 *)kmem_alloc(size,
1154 	    KM_NOSLEEP))) {
1155 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1156 		    "%s PRLO: Unable to allocate buffer.",
1157 		    emlxs_sd_els_event.label);
1158 
1159 		return;
1160 	}
1161 
1162 	/*
1163 	 * we are using version field to store subtype, libdfc
1164 	 * will fix this up before returning data to app.
1165 	 */
1166 	bp->sd_prlor_version = SD_ELS_SUBCATEGORY_PRLO_RCV;
1167 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_prlor_remoteport,
1168 	    sizeof (HBA_WWN));
1169 
1170 	emlxs_event(port, &emlxs_sd_els_event, bp, size);
1171 
1172 	return;
1173 
1174 } /* emlxs_log_sd_prlo_event() */
1175 
1176 
1177 extern void
1178 emlxs_log_sd_lsrjt_event(emlxs_port_t *port, HBA_WWN *remoteport,
1179     uint32_t orig_cmd, uint32_t reason, uint32_t reason_expl)
1180 {
1181 	struct sd_lsrjt_rcv_v0	*bp;
1182 	uint32_t		size;
1183 
1184 	/* Check if the event is being requested */
1185 	if (emlxs_event_check(port, &emlxs_sd_els_event) == 0) {
1186 		return;
1187 	}
1188 
1189 	size = sizeof (struct sd_lsrjt_rcv_v0);
1190 
1191 	if (!(bp = (struct sd_lsrjt_rcv_v0 *)kmem_alloc(size,
1192 	    KM_NOSLEEP))) {
1193 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1194 		    "%s LSRJT: Unable to allocate buffer.",
1195 		    emlxs_sd_els_event.label);
1196 
1197 		return;
1198 	}
1199 
1200 	/*
1201 	 * we are using version field to store subtype, libdfc
1202 	 * will fix this up before returning data to app.
1203 	 */
1204 	bp->sd_lsrjtr_version = SD_ELS_SUBCATEGORY_LSRJT_RCV;
1205 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_lsrjtr_remoteport,
1206 	    sizeof (HBA_WWN));
1207 	bp->sd_lsrjtr_original_cmd = orig_cmd;
1208 	bp->sd_lsrjtr_reasoncode = reason;
1209 	bp->sd_lsrjtr_reasoncodeexpl = reason_expl;
1210 
1211 	emlxs_event(port, &emlxs_sd_els_event, bp, size);
1212 
1213 	return;
1214 
1215 } /* emlxs_log_sd_lsrjt_event() */
1216 
1217 
1218 extern void
1219 emlxs_log_sd_fc_bsy_event(emlxs_port_t *port, HBA_WWN *remoteport)
1220 {
1221 	struct sd_pbsy_rcv_v0	*bp;
1222 	uint32_t		size;
1223 
1224 	/* Check if the event is being requested */
1225 	if (emlxs_event_check(port, &emlxs_sd_fabric_event) == 0) {
1226 		return;
1227 	}
1228 
1229 	size = sizeof (struct sd_pbsy_rcv_v0);
1230 
1231 	if (!(bp = (struct sd_pbsy_rcv_v0 *)kmem_alloc(size,
1232 	    KM_NOSLEEP))) {
1233 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1234 		    "%s BSY: Unable to allocate buffer.",
1235 		    emlxs_sd_fabric_event.label);
1236 
1237 		return;
1238 	}
1239 
1240 	/*
1241 	 * we are using version field to store subtype, libdfc
1242 	 * will fix this up before returning data to app.
1243 	 */
1244 	if (remoteport == NULL)
1245 		bp->sd_pbsyr_evt_version = SD_FABRIC_SUBCATEGORY_FABRIC_BUSY;
1246 	else
1247 	{
1248 		bp->sd_pbsyr_evt_version = SD_FABRIC_SUBCATEGORY_PORT_BUSY;
1249 		bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_pbsyr_rport,
1250 		    sizeof (HBA_WWN));
1251 	}
1252 
1253 	emlxs_event(port, &emlxs_sd_fabric_event, bp, size);
1254 
1255 	return;
1256 
1257 } /* emlxs_log_sd_fc_bsy_event() */
1258 
1259 
1260 extern void
1261 emlxs_log_sd_fc_rdchk_event(emlxs_port_t *port, HBA_WWN *remoteport,
1262     uint32_t lun, uint32_t opcode, uint32_t fcp_param)
1263 {
1264 	struct sd_fcprdchkerr_v0	*bp;
1265 	uint32_t			size;
1266 
1267 	/* Check if the event is being requested */
1268 	if (emlxs_event_check(port, &emlxs_sd_fabric_event) == 0) {
1269 		return;
1270 	}
1271 
1272 	size = sizeof (struct sd_fcprdchkerr_v0);
1273 
1274 	if (!(bp = (struct sd_fcprdchkerr_v0 *)kmem_alloc(size,
1275 	    KM_NOSLEEP))) {
1276 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1277 		    "%s RDCHK: Unable to allocate buffer.",
1278 		    emlxs_sd_fabric_event.label);
1279 
1280 		return;
1281 	}
1282 
1283 	/*
1284 	 * we are using version field to store subtype, libdfc
1285 	 * will fix this up before returning data to app.
1286 	 */
1287 	bp->sd_fcprdchkerr_version = SD_FABRIC_SUBCATEGORY_FCPRDCHKERR;
1288 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_fcprdchkerr_rport,
1289 	    sizeof (HBA_WWN));
1290 	bp->sd_fcprdchkerr_lun = lun;
1291 	bp->sd_fcprdchkerr_opcode = opcode;
1292 	bp->sd_fcprdchkerr_fcpiparam = fcp_param;
1293 
1294 	emlxs_event(port, &emlxs_sd_fabric_event, bp, size);
1295 
1296 	return;
1297 
1298 } /* emlxs_log_sd_rdchk_event() */
1299 
1300 
1301 extern void
1302 emlxs_log_sd_scsi_event(emlxs_port_t *port, uint32_t type,
1303     HBA_WWN *remoteport, int32_t lun)
1304 {
1305 	struct sd_scsi_generic_v0	*bp;
1306 	uint32_t			size;
1307 
1308 	/* Check if the event is being requested */
1309 	if (emlxs_event_check(port, &emlxs_sd_scsi_event) == 0) {
1310 		return;
1311 	}
1312 
1313 	size = sizeof (struct sd_scsi_generic_v0);
1314 
1315 	if (!(bp = (struct sd_scsi_generic_v0 *)kmem_alloc(size,
1316 	    KM_NOSLEEP))) {
1317 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1318 		    "%s: Unable to allocate buffer.",
1319 		    emlxs_sd_scsi_event.label);
1320 
1321 		return;
1322 	}
1323 
1324 	/*
1325 	 * we are using version field to store subtype, libdfc
1326 	 * will fix this up before returning data to app.
1327 	 */
1328 	bp->sd_scsi_generic_version = type;
1329 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_scsi_generic_rport,
1330 	    sizeof (HBA_WWN));
1331 	bp->sd_scsi_generic_lun = lun;
1332 
1333 	emlxs_event(port, &emlxs_sd_scsi_event, bp, size);
1334 
1335 	return;
1336 
1337 } /* emlxs_log_sd_scsi_event() */
1338 
1339 
1340 extern void
1341 emlxs_log_sd_scsi_check_event(emlxs_port_t *port, HBA_WWN *remoteport,
1342     uint32_t lun, uint32_t cmdcode, uint32_t sensekey,
1343     uint32_t asc, uint32_t ascq)
1344 {
1345 	struct sd_scsi_checkcond_v0	*bp;
1346 	uint32_t			size;
1347 
1348 	/* Check if the event is being requested */
1349 	if (emlxs_event_check(port, &emlxs_sd_scsi_event) == 0) {
1350 		return;
1351 	}
1352 
1353 	size = sizeof (struct sd_scsi_checkcond_v0);
1354 
1355 	if (!(bp = (struct sd_scsi_checkcond_v0 *)kmem_alloc(size,
1356 	    KM_NOSLEEP))) {
1357 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
1358 		    "%s CHECK: Unable to allocate buffer.",
1359 		    emlxs_sd_scsi_event.label);
1360 
1361 		return;
1362 	}
1363 
1364 	/*
1365 	 * we are using version field to store subtype, libdfc
1366 	 * will fix this up before returning data to app.
1367 	 */
1368 	bp->sd_scsi_checkcond_version = SD_SCSI_SUBCATEGORY_CHECKCONDITION;
1369 	bcopy((uint8_t *)remoteport, (uint8_t *)&bp->sd_scsi_checkcond_rport,
1370 	    sizeof (HBA_WWN));
1371 	bp->sd_scsi_checkcond_lun = lun;
1372 	bp->sd_scsi_checkcond_cmdcode = cmdcode;
1373 	bp->sd_scsi_checkcond_sensekey = sensekey;
1374 	bp->sd_scsi_checkcond_asc = asc;
1375 	bp->sd_scsi_checkcond_ascq = ascq;
1376 
1377 	emlxs_event(port, &emlxs_sd_scsi_event, bp, size);
1378 
1379 	return;
1380 
1381 } /* emlxs_log_sd_scsi_check_event() */
1382 
1383 
1384 void
1385 emlxs_get_sd_event(emlxs_port_t *port, emlxs_dfc_event_t *dfc_event,
1386     uint32_t sleep)
1387 {
1388 	emlxs_hba_t *hba = HBA;
1389 	emlxs_event_queue_t *eventq = &EVENTQ;
1390 	emlxs_event_entry_t *entry;
1391 	uint32_t found;
1392 	uint32_t mask;
1393 	uint32_t i;
1394 	uint32_t size = 0;
1395 	uint32_t rc;
1396 
1397 	if (dfc_event->dataout && dfc_event->size) {
1398 		size = dfc_event->size;
1399 	}
1400 	dfc_event->size = 0;
1401 
1402 	/* Calculate the event index */
1403 	mask = dfc_event->event;
1404 	for (i = 0; i < 32; i++) {
1405 		if (mask & 0x01) {
1406 			break;
1407 		}
1408 
1409 		mask >>= 1;
1410 	}
1411 
1412 	if (i == 32) {
1413 		return;
1414 	}
1415 
1416 	mutex_enter(&eventq->lock);
1417 
1418 wait_for_event:
1419 
1420 	/* Check if no new event has ocurred */
1421 	if (dfc_event->last_id == eventq->last_id[i]) {
1422 		if (!sleep) {
1423 			mutex_exit(&eventq->lock);
1424 			return;
1425 		}
1426 
1427 		/* While event is active and no new event has been logged */
1428 		while ((dfc_event->event & port->sd_event_mask) &&
1429 		    (dfc_event->last_id == eventq->last_id[i])) {
1430 			rc = cv_wait_sig(&eventq->lock_cv, &eventq->lock);
1431 
1432 			/* Check if thread was killed by kernel */
1433 			if (rc == 0) {
1434 				dfc_event->pid = 0;
1435 				dfc_event->event = 0;
1436 				mutex_exit(&eventq->lock);
1437 				return;
1438 			}
1439 		}
1440 
1441 		/* If the event is no longer registered then return */
1442 		if (!(dfc_event->event & port->sd_event_mask)) {
1443 			mutex_exit(&eventq->lock);
1444 			return;
1445 		}
1446 	}
1447 
1448 	/* !!! An event has occurred since last_id !!! */
1449 
1450 	/* Check if event data is not being requested */
1451 	if (!size) {
1452 		/* If so, then just return the last event id */
1453 		dfc_event->last_id = eventq->last_id[i];
1454 
1455 		mutex_exit(&eventq->lock);
1456 		return;
1457 	}
1458 
1459 	/* !!! The requester wants the next event buffer !!! */
1460 
1461 	found = 0;
1462 	entry = eventq->first;
1463 	while (entry) {
1464 		if ((entry->id > dfc_event->last_id) &&
1465 		    (entry->port == (void *)port) &&
1466 		    (entry->evt->mask == dfc_event->event)) {
1467 			found = 1;
1468 			break;
1469 		}
1470 
1471 		entry = entry->next;
1472 	}
1473 
1474 	if (!found) {
1475 		/* Update last_id to the last known event */
1476 		dfc_event->last_id = eventq->last_id[i];
1477 
1478 		/* Try waiting again if we can */
1479 		goto wait_for_event;
1480 	}
1481 
1482 	/* !!! Next event found !!! */
1483 
1484 	/* Copy the context buffer to the buffer provided */
1485 	if (entry->bp && entry->size) {
1486 		if (entry->size < size) {
1487 			size = entry->size;
1488 		}
1489 
1490 		bcopy((void *)entry->bp, dfc_event->dataout, size);
1491 
1492 		/* Event has been retrieved by SANDIAG */
1493 		entry->flag |= EMLXS_SD_EVENT_DONE;
1494 
1495 		dfc_event->size = size;
1496 	}
1497 
1498 	dfc_event->last_id = entry->id;
1499 
1500 	mutex_exit(&eventq->lock);
1501 
1502 	return;
1503 
1504 } /* emlxs_get_sd_event */
1505 #endif /* SAN_DIAG_SUPPORT */
1506