182527734SSukumar Swaminathan /*
282527734SSukumar Swaminathan  * CDDL HEADER START
382527734SSukumar Swaminathan  *
482527734SSukumar Swaminathan  * The contents of this file are subject to the terms of the
582527734SSukumar Swaminathan  * Common Development and Distribution License (the "License").
682527734SSukumar Swaminathan  * You may not use this file except in compliance with the License.
782527734SSukumar Swaminathan  *
88f23e9faSHans Rosenfeld  * You can obtain a copy of the license at
98f23e9faSHans Rosenfeld  * http://www.opensource.org/licenses/cddl1.txt.
1082527734SSukumar Swaminathan  * See the License for the specific language governing permissions
1182527734SSukumar Swaminathan  * and limitations under the License.
1282527734SSukumar Swaminathan  *
1382527734SSukumar Swaminathan  * When distributing Covered Code, include this CDDL HEADER in each
1482527734SSukumar Swaminathan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1582527734SSukumar Swaminathan  * If applicable, add the following below this CDDL HEADER, with the
1682527734SSukumar Swaminathan  * fields enclosed by brackets "[]" replaced with your own identifying
1782527734SSukumar Swaminathan  * information: Portions Copyright [yyyy] [name of copyright owner]
1882527734SSukumar Swaminathan  *
1982527734SSukumar Swaminathan  * CDDL HEADER END
2082527734SSukumar Swaminathan  */
2182527734SSukumar Swaminathan 
2282527734SSukumar Swaminathan /*
238f23e9faSHans Rosenfeld  * Copyright (c) 2004-2012 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25*a3170057SPaul Winder  * Copyright 2020 RackTop Systems, Inc.
2682527734SSukumar Swaminathan  */
2782527734SSukumar Swaminathan 
2882527734SSukumar Swaminathan #define	DEF_EVENT_STRUCT  /* Needed for emlxs_events.h in emlxs_event.h */
2982527734SSukumar Swaminathan #include <emlxs.h>
3082527734SSukumar Swaminathan 
3182527734SSukumar Swaminathan 
3282527734SSukumar Swaminathan /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
3382527734SSukumar Swaminathan EMLXS_MSG_DEF(EMLXS_EVENT_C);
3482527734SSukumar Swaminathan 
3582527734SSukumar Swaminathan 
3682527734SSukumar Swaminathan static uint32_t emlxs_event_check(emlxs_port_t *port, emlxs_event_t *evt);
3782527734SSukumar Swaminathan static void emlxs_event_destroy(emlxs_hba_t *hba, emlxs_event_entry_t *entry);
3882527734SSukumar Swaminathan 
3982527734SSukumar Swaminathan extern void
emlxs_null_func()4082527734SSukumar Swaminathan emlxs_null_func() {}
4182527734SSukumar Swaminathan 
4282527734SSukumar Swaminathan 
4382527734SSukumar Swaminathan static uint32_t
emlxs_event_check(emlxs_port_t * port,emlxs_event_t * evt)4482527734SSukumar Swaminathan emlxs_event_check(emlxs_port_t *port, emlxs_event_t *evt)
4582527734SSukumar Swaminathan {
4682527734SSukumar Swaminathan 	emlxs_hba_t *hba = HBA;
4782527734SSukumar Swaminathan 
4882527734SSukumar Swaminathan 	/* Check if the event is being requested */
4982527734SSukumar Swaminathan 	if ((hba->event_mask & evt->mask)) {
5082527734SSukumar Swaminathan 		return (1);
5182527734SSukumar Swaminathan 	}
5282527734SSukumar Swaminathan 
5382527734SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
5482527734SSukumar Swaminathan 	if ((port->sd_event_mask & evt->mask)) {
5582527734SSukumar Swaminathan 		return (1);
5682527734SSukumar Swaminathan 	}
5782527734SSukumar Swaminathan #endif /* SAN_DIAG_SUPPORT */
5882527734SSukumar Swaminathan 
5982527734SSukumar Swaminathan 	return (0);
6082527734SSukumar Swaminathan 
6182527734SSukumar Swaminathan } /* emlxs_event_check() */
6282527734SSukumar Swaminathan 
6382527734SSukumar Swaminathan 
6482527734SSukumar Swaminathan extern uint32_t
emlxs_event_queue_create(emlxs_hba_t * hba)6582527734SSukumar Swaminathan emlxs_event_queue_create(emlxs_hba_t *hba)
6682527734SSukumar Swaminathan {
6782527734SSukumar Swaminathan 	emlxs_event_queue_t *eventq = &EVENTQ;
6882527734SSukumar Swaminathan 	ddi_iblock_cookie_t iblock;
6982527734SSukumar Swaminathan 
7082527734SSukumar Swaminathan 	/* Clear the queue */
7182527734SSukumar Swaminathan 	bzero(eventq, sizeof (emlxs_event_queue_t));
7282527734SSukumar Swaminathan 
738f23e9faSHans Rosenfeld 	cv_init(&eventq->lock_cv, NULL, CV_DRIVER, NULL);
7482527734SSukumar Swaminathan 
7582527734SSukumar Swaminathan 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
7682527734SSukumar Swaminathan 		/* Get the current interrupt block cookie */
7782527734SSukumar Swaminathan 		(void) ddi_get_iblock_cookie(hba->dip, (uint_t)EMLXS_INUMBER,
7882527734SSukumar Swaminathan 		    &iblock);
7982527734SSukumar Swaminathan 
8082527734SSukumar Swaminathan 		/* Create the mutex lock */
818f23e9faSHans Rosenfeld 		mutex_init(&eventq->lock, NULL, MUTEX_DRIVER, (void *)iblock);
8282527734SSukumar Swaminathan 	}
8382527734SSukumar Swaminathan #ifdef  MSI_SUPPORT
8482527734SSukumar Swaminathan 	else {
85a9800bebSGarrett D'Amore 		/* Create event mutex lock */
868f23e9faSHans Rosenfeld 		mutex_init(&eventq->lock, NULL, MUTEX_DRIVER,
87a9800bebSGarrett D'Amore 		    DDI_INTR_PRI(hba->intr_arg));
8882527734SSukumar Swaminathan 	}
8982527734SSukumar Swaminathan #endif
9082527734SSukumar Swaminathan 
9182527734SSukumar Swaminathan 	return (1);
9282527734SSukumar Swaminathan 
9382527734SSukumar Swaminathan } /* emlxs_event_queue_create() */
9482527734SSukumar Swaminathan 
9582527734SSukumar Swaminathan 
9682527734SSukumar Swaminathan extern void
emlxs_event_queue_destroy(emlxs_hba_t * hba)9782527734SSukumar Swaminathan emlxs_event_queue_destroy(emlxs_hba_t *hba)
9882527734SSukumar Swaminathan {
9982527734SSukumar Swaminathan 	emlxs_port_t *vport;
10082527734SSukumar Swaminathan 	emlxs_event_queue_t *eventq = &EVENTQ;
10182527734SSukumar Swaminathan 	uint32_t i;
10282527734SSukumar Swaminathan 	uint32_t wakeup = 0;
10382527734SSukumar Swaminathan 
10482527734SSukumar Swaminathan 	mutex_enter(&eventq->lock);
10582527734SSukumar Swaminathan 
10682527734SSukumar Swaminathan 	/* Clear all event masks and broadcast a wakeup */
10782527734SSukumar Swaminathan 	/* to clear any sleeping threads */
10882527734SSukumar Swaminathan 	if (hba->event_mask) {
10982527734SSukumar Swaminathan 		hba->event_mask = 0;
11082527734SSukumar Swaminathan 		hba->event_timer = 0;
11182527734SSukumar Swaminathan 		wakeup = 1;
11282527734SSukumar Swaminathan 	}
11382527734SSukumar Swaminathan 
11482527734SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
11582527734SSukumar Swaminathan 		vport = &VPORT(i);
11682527734SSukumar Swaminathan 
11782527734SSukumar Swaminathan 		if (vport->sd_event_mask) {
11882527734SSukumar Swaminathan 			vport->sd_event_mask = 0;
11982527734SSukumar Swaminathan 			wakeup = 1;
12082527734SSukumar Swaminathan 		}
12182527734SSukumar Swaminathan 	}
12282527734SSukumar Swaminathan 
12382527734SSukumar Swaminathan 	if (wakeup) {
12482527734SSukumar Swaminathan 		cv_broadcast(&eventq->lock_cv);
12582527734SSukumar Swaminathan 
12682527734SSukumar Swaminathan 		mutex_exit(&eventq->lock);
1278f23e9faSHans Rosenfeld 		BUSYWAIT_MS(10);
12882527734SSukumar Swaminathan 		mutex_enter(&eventq->lock);
12982527734SSukumar Swaminathan 	}
13082527734SSukumar Swaminathan 
13182527734SSukumar Swaminathan 	/* Destroy the remaining events */
13282527734SSukumar Swaminathan 	while (eventq->first) {
13382527734SSukumar Swaminathan 		emlxs_event_destroy(hba, eventq->first);
13482527734SSukumar Swaminathan 	}
13582527734SSukumar Swaminathan 
13682527734SSukumar Swaminathan 	mutex_exit(&eventq->lock);
13782527734SSukumar Swaminathan 
13882527734SSukumar Swaminathan 	/* Destroy the queue lock */
13982527734SSukumar Swaminathan 	mutex_destroy(&eventq->lock);
14082527734SSukumar Swaminathan 	cv_destroy(&eventq->lock_cv);
14182527734SSukumar Swaminathan 
14282527734SSukumar Swaminathan 	/* Clear the queue */
14382527734SSukumar Swaminathan 	bzero(eventq, sizeof (emlxs_event_queue_t));
14482527734SSukumar Swaminathan 
14582527734SSukumar Swaminathan 	return;
14682527734SSukumar Swaminathan 
14782527734SSukumar Swaminathan } /* emlxs_event_queue_destroy() */
14882527734SSukumar Swaminathan 
14982527734SSukumar Swaminathan 
15082527734SSukumar Swaminathan /* Event queue lock must be held */
15182527734SSukumar Swaminathan static void
emlxs_event_destroy(emlxs_hba_t * hba,emlxs_event_entry_t * entry)15282527734SSukumar Swaminathan emlxs_event_destroy(emlxs_hba_t *hba, emlxs_event_entry_t *entry)
15382527734SSukumar Swaminathan {
15482527734SSukumar Swaminathan 	emlxs_event_queue_t *eventq = &EVENTQ;
15582527734SSukumar Swaminathan 	emlxs_port_t *port;
15682527734SSukumar Swaminathan 	uint32_t missed = 0;
15782527734SSukumar Swaminathan 
15882527734SSukumar Swaminathan 	port = (emlxs_port_t *)entry->port;
15982527734SSukumar Swaminathan 
16082527734SSukumar Swaminathan 	eventq->count--;
16182527734SSukumar Swaminathan 	if (eventq->count == 0) {
16282527734SSukumar Swaminathan 		eventq->first = NULL;
16382527734SSukumar Swaminathan 		eventq->last = NULL;
16482527734SSukumar Swaminathan 	} else {
16582527734SSukumar Swaminathan 		if (entry->prev) {
16682527734SSukumar Swaminathan 			entry->prev->next = entry->next;
16782527734SSukumar Swaminathan 		}
16882527734SSukumar Swaminathan 		if (entry->next) {
16982527734SSukumar Swaminathan 			entry->next->prev = entry->prev;
17082527734SSukumar Swaminathan 		}
17182527734SSukumar Swaminathan 		if (eventq->first == entry) {
17282527734SSukumar Swaminathan 			eventq->first = entry->next;
17382527734SSukumar Swaminathan 		}
17482527734SSukumar Swaminathan 		if (eventq->last == entry) {
17582527734SSukumar Swaminathan 			eventq->last = entry->prev;
17682527734SSukumar Swaminathan 		}
17782527734SSukumar Swaminathan 	}
17882527734SSukumar Swaminathan 
17982527734SSukumar Swaminathan 	entry->prev = NULL;
18082527734SSukumar Swaminathan 	entry->next = NULL;
18182527734SSukumar Swaminathan 
18282527734SSukumar Swaminathan 	if ((entry->evt->mask == EVT_LINK) ||
18382527734SSukumar Swaminathan 	    (entry->evt->mask == EVT_RSCN)) {
18482527734SSukumar Swaminathan 		if (!(entry->flag & EMLXS_DFC_EVENT_DONE)) {
18582527734SSukumar Swaminathan 			hba->hba_event.missed++;
18682527734SSukumar Swaminathan 			missed = 1;
18782527734SSukumar Swaminathan 		}
18882527734SSukumar Swaminathan 	}
18982527734SSukumar Swaminathan 
19082527734SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_dequeued_msg,
19182527734SSukumar Swaminathan 	    "%s[%d]: flag=%x missed=%d cnt=%d",
19282527734SSukumar Swaminathan 	    entry->evt->label, entry->id, entry->flag, missed, eventq->count);
19382527734SSukumar Swaminathan 
19482527734SSukumar Swaminathan 	/* Call notification handler */
1958f23e9faSHans Rosenfeld 	if (entry->evt->destroy != emlxs_null_func) {
1968f23e9faSHans Rosenfeld 		entry->evt->destroy(entry);
1978f23e9faSHans Rosenfeld 	}
19882527734SSukumar Swaminathan 
19982527734SSukumar Swaminathan 	/* Free context buffer */
20082527734SSukumar Swaminathan 	if (entry->bp && entry->size) {
20182527734SSukumar Swaminathan 		kmem_free(entry->bp, entry->size);
20282527734SSukumar Swaminathan 	}
20382527734SSukumar Swaminathan 
20482527734SSukumar Swaminathan 	/* Free entry buffer */
20582527734SSukumar Swaminathan 	kmem_free(entry, sizeof (emlxs_event_entry_t));
20682527734SSukumar Swaminathan 
20782527734SSukumar Swaminathan 	return;
20882527734SSukumar Swaminathan 
20982527734SSukumar Swaminathan } /* emlxs_event_destroy() */
21082527734SSukumar Swaminathan 
21182527734SSukumar Swaminathan 
21282527734SSukumar Swaminathan extern void
emlxs_event(emlxs_port_t * port,emlxs_event_t * evt,void * bp,uint32_t size)21382527734SSukumar Swaminathan emlxs_event(emlxs_port_t *port, emlxs_event_t *evt, void *bp, uint32_t size)
21482527734SSukumar Swaminathan {
21582527734SSukumar Swaminathan 	emlxs_hba_t *hba = HBA;
21682527734SSukumar Swaminathan 	emlxs_event_queue_t *eventq = &EVENTQ;
21782527734SSukumar Swaminathan 	emlxs_event_entry_t *entry;
21882527734SSukumar Swaminathan 	uint32_t i;
21982527734SSukumar Swaminathan 	uint32_t mask;
22082527734SSukumar Swaminathan 
22182527734SSukumar Swaminathan 	if (emlxs_event_check(port, evt) == 0) {
22282527734SSukumar Swaminathan 		goto failed;
22382527734SSukumar Swaminathan 	}
22482527734SSukumar Swaminathan 
22582527734SSukumar Swaminathan 	/* Create event entry */
22682527734SSukumar Swaminathan 	if (!(entry = (emlxs_event_entry_t *)kmem_alloc(
22782527734SSukumar Swaminathan 	    sizeof (emlxs_event_entry_t), KM_NOSLEEP))) {
22882527734SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_debug_msg,
22982527734SSukumar Swaminathan 		    "%s: Unable to allocate event entry.", evt->label);
23082527734SSukumar Swaminathan 
23182527734SSukumar Swaminathan 		goto failed;
23282527734SSukumar Swaminathan 	}
23382527734SSukumar Swaminathan 
23482527734SSukumar Swaminathan 	/* Initialize */
23582527734SSukumar Swaminathan 	bzero(entry, sizeof (emlxs_event_entry_t));
23682527734SSukumar Swaminathan 
23782527734SSukumar Swaminathan 	entry->evt = evt;
23882527734SSukumar Swaminathan 	entry->port = (void *)port;
23982527734SSukumar Swaminathan 	entry->bp = bp;
24082527734SSukumar Swaminathan 	entry->size = size;
24182527734SSukumar Swaminathan 
24282527734SSukumar Swaminathan 	mutex_enter(&eventq->lock);
24382527734SSukumar Swaminathan 
24482527734SSukumar Swaminathan 	/* Set the event timer */
24582527734SSukumar Swaminathan 	entry->timestamp = hba->timer_tics;
24682527734SSukumar Swaminathan 	if (evt->timeout) {
24782527734SSukumar Swaminathan 		entry->timer = entry->timestamp + evt->timeout;
24882527734SSukumar Swaminathan 	}
24982527734SSukumar Swaminathan 
2508f23e9faSHans Rosenfeld 	/* Eventq id starts with 1 */
2518f23e9faSHans Rosenfeld 	if (eventq->next_id == 0) {
2528f23e9faSHans Rosenfeld 		eventq->next_id = 1;
2538f23e9faSHans Rosenfeld 	}
2548f23e9faSHans Rosenfeld 
25582527734SSukumar Swaminathan 	/* Set the event id */
25682527734SSukumar Swaminathan 	entry->id = eventq->next_id++;
25782527734SSukumar Swaminathan 
25882527734SSukumar Swaminathan 	/* Set last event table */
25982527734SSukumar Swaminathan 	mask = evt->mask;
26082527734SSukumar Swaminathan 	for (i = 0; i < 32; i++) {
26182527734SSukumar Swaminathan 		if (mask & 0x01) {
26282527734SSukumar Swaminathan 			eventq->last_id[i] = entry->id;
26382527734SSukumar Swaminathan 		}
26482527734SSukumar Swaminathan 		mask >>= 1;
26582527734SSukumar Swaminathan 	}
26682527734SSukumar Swaminathan 
26782527734SSukumar Swaminathan 	/* Put event on bottom of queue */
26882527734SSukumar Swaminathan 	entry->next = NULL;
26982527734SSukumar Swaminathan 	if (eventq->count == 0) {
27082527734SSukumar Swaminathan 		entry->prev = NULL;
27182527734SSukumar Swaminathan 		eventq->first = entry;
27282527734SSukumar Swaminathan 		eventq->last = entry;
27382527734SSukumar Swaminathan 	} else {
27482527734SSukumar Swaminathan 		entry->prev = eventq->last;
27582527734SSukumar Swaminathan 		entry->prev->next = entry;
27682527734SSukumar Swaminathan 		eventq->last = entry;
27782527734SSukumar Swaminathan 	}
27882527734SSukumar Swaminathan 	eventq->count++;
27982527734SSukumar Swaminathan 
28082527734SSukumar Swaminathan 	if ((entry->evt->mask == EVT_LINK) ||
28182527734SSukumar Swaminathan 	    (entry->evt->mask == EVT_RSCN)) {
28282527734SSukumar Swaminathan 		hba->hba_event.new++;
28382527734SSukumar Swaminathan 	}
28482527734SSukumar Swaminathan 
28582527734SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_event_queued_msg,
28682527734SSukumar Swaminathan 	    "%s[%d]: bp=%p size=%d cnt=%d", entry->evt->label,
28782527734SSukumar Swaminathan 	    entry->id, bp, size, eventq->count);
28882527734SSukumar Swaminathan 
28982527734SSukumar Swaminathan 	/* Broadcast the event */
29082527734SSukumar Swaminathan 	cv_broadcast(&eventq->lock_cv);
29182527734SSukumar Swaminathan 
29282527734SSukumar Swaminathan 	mutex_exit(&eventq->lock);
29382527734SSukumar Swaminathan 
29482527734SSukumar Swaminathan 	return;
29582527734SSukumar Swaminathan 
29682527734SSukumar Swaminathan failed:
29782527734SSukumar Swaminathan 
2988f23e9faSHans Rosenfeld 	if (bp && size) {
2998f23e9faSHans Rosenfeld 		kmem_free(bp, size);
30082527734SSukumar Swaminathan 	}
30182527734SSukumar Swaminathan 
30282527734SSukumar Swaminathan 	return;
30382527734SSukumar Swaminathan 
30482527734SSukumar Swaminathan } /* emlxs_event() */
30582527734SSukumar Swaminathan 
30682527734SSukumar Swaminathan 
30782527734SSukumar Swaminathan extern void
emlxs_timer_check_events(emlxs_hba_t * hba)30882527734SSukumar Swaminathan emlxs_timer_check_events(emlxs_hba_t *hba)
30982527734SSukumar Swaminathan {
31082527734SSukumar Swaminathan 	emlxs_config_t *cfg = &CFG;
31182527734SSukumar Swaminathan 	emlxs_event_queue_t *eventq = &EVENTQ;
31282527734SSukumar Swaminathan 	emlxs_event_entry_t *entry;
31382527734SSukumar Swaminathan 	emlxs_event_entry_t *next;
31482527734SSukumar Swaminathan 
31582527734SSukumar Swaminathan 	if (!cfg[CFG_TIMEOUT_ENABLE].current) {
31682527734SSukumar Swaminathan 		return;
31782527734SSukumar Swaminathan 	}
31882527734SSukumar Swaminathan 
31982527734SSukumar Swaminathan 	if ((hba->event_timer > hba->timer_tics)) {
32082527734SSukumar Swaminathan 		return;
32182527734SSukumar Swaminathan 	}
32282527734SSukumar Swaminathan 
32382527734SSukumar Swaminathan 	if (eventq->count) {
32482527734SSukumar Swaminathan 		mutex_enter(&eventq->lock);
32582527734SSukumar Swaminathan 
32682527734SSukumar Swaminathan 		entry = eventq->first;
32782527734SSukumar Swaminathan 		while (entry) {
32882527734SSukumar Swaminathan 			if ((!entry->timer) ||
32982527734SSukumar Swaminathan 			    (entry->timer > hba->timer_tics)) {
33082527734SSukumar Swaminathan 				entry = entry->next;
33182527734SSukumar Swaminathan 				continue;
33282527734SSukumar Swaminathan 			}
33382527734SSukumar Swaminathan 
33482527734SSukumar Swaminathan 			/* Event timed out, destroy it */
33582527734SSukumar Swaminathan 			next = entry->next;
33682527734SSukumar Swaminathan 			emlxs_event_destroy(hba, entry);
33782527734SSukumar Swaminathan 			entry = next;
33882527734SSukumar Swaminathan 		}
33982527734SSukumar Swaminathan 
34082527734SSukumar Swaminathan 		mutex_exit(&eventq->lock);
34182527734SSukumar Swaminathan 	}
34282527734SSukumar Swaminathan 
343