1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
88f23e9faSHans Rosenfeld  * You can obtain a copy of the license at
98f23e9faSHans Rosenfeld  * http://www.opensource.org/licenses/cddl1.txt.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22fcf3ce44SJohn Forte /*
238f23e9faSHans Rosenfeld  * Copyright (c) 2004-2012 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25*a3170057SPaul Winder  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26*a3170057SPaul Winder  * Copyright 2020 RackTop Systems, Inc.
27fcf3ce44SJohn Forte  */
28fcf3ce44SJohn Forte 
2982527734SSukumar Swaminathan #define	EMLXS_FW_TABLE_DEF
3082527734SSukumar Swaminathan #define	EMLXS_MODEL_DEF
31fcf3ce44SJohn Forte 
3282527734SSukumar Swaminathan #include <emlxs.h>
33fcf3ce44SJohn Forte 
3482527734SSukumar Swaminathan /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
3582527734SSukumar Swaminathan EMLXS_MSG_DEF(EMLXS_HBA_C);
36fcf3ce44SJohn Forte 
37a9800bebSGarrett D'Amore 
3882527734SSukumar Swaminathan static void emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp,
3982527734SSukumar Swaminathan     IOCBQ *iocbq);
40291a2b48SSukumar Swaminathan 
41a9800bebSGarrett D'Amore static void emlxs_pci_cap_offsets(emlxs_hba_t *hba);
42a9800bebSGarrett D'Amore 
43fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
4482527734SSukumar Swaminathan uint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
4582527734SSukumar Swaminathan 	{EMLXS_MSI_MAP1, EMLXS_MSI_MAP2, EMLXS_MSI_MAP4, EMLXS_MSI_MAP8};
4682527734SSukumar Swaminathan uint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
4782527734SSukumar Swaminathan 	{EMLXS_MSI0_MASK1, EMLXS_MSI0_MASK2, EMLXS_MSI0_MASK4,
4882527734SSukumar Swaminathan 	EMLXS_MSI0_MASK8};
49291a2b48SSukumar Swaminathan #endif /* MSI_SUPPORT */
50fcf3ce44SJohn Forte 
5182527734SSukumar Swaminathan emlxs_firmware_t emlxs_fw_table[] = EMLXS_FW_TABLE;
5282527734SSukumar Swaminathan int emlxs_fw_count = sizeof (emlxs_fw_table) / sizeof (emlxs_firmware_t);
53291a2b48SSukumar Swaminathan 
54a9800bebSGarrett D'Amore emlxs_table_t emlxs_pci_cap[] = {
55a9800bebSGarrett D'Amore 	{PCI_CAP_ID_PM, "PCI_CAP_ID_PM"},
56a9800bebSGarrett D'Amore 	{PCI_CAP_ID_AGP, "PCI_CAP_ID_AGP"},
57a9800bebSGarrett D'Amore 	{PCI_CAP_ID_VPD, "PCI_CAP_ID_VPD"},
58a9800bebSGarrett D'Amore 	{PCI_CAP_ID_SLOT_ID, "PCI_CAP_ID_SLOT_ID"},
59a9800bebSGarrett D'Amore 	{PCI_CAP_ID_MSI, "PCI_CAP_ID_MSI"},
60a9800bebSGarrett D'Amore 	{PCI_CAP_ID_cPCI_HS, "PCI_CAP_ID_cPCI_HS"},
61a9800bebSGarrett D'Amore 	{PCI_CAP_ID_PCIX, "PCI_CAP_ID_PCIX"},
62a9800bebSGarrett D'Amore 	{PCI_CAP_ID_HT, "PCI_CAP_ID_HT"},
63a9800bebSGarrett D'Amore 	{PCI_CAP_ID_VS, "PCI_CAP_ID_VS"},
64a9800bebSGarrett D'Amore 	{PCI_CAP_ID_DEBUG_PORT, "PCI_CAP_ID_DEBUG_PORT"},
65a9800bebSGarrett D'Amore 	{PCI_CAP_ID_cPCI_CRC, "PCI_CAP_ID_cPCI_CRC"},
67a9800bebSGarrett D'Amore 	{PCI_CAP_ID_P2P_SUBSYS, "PCI_CAP_ID_P2P_SUBSYS"},
68a9800bebSGarrett D'Amore 	{PCI_CAP_ID_AGP_8X, "PCI_CAP_ID_AGP_8X"},
69a9800bebSGarrett D'Amore 	{PCI_CAP_ID_SECURE_DEV, "PCI_CAP_ID_SECURE_DEV"},
70a9800bebSGarrett D'Amore 	{PCI_CAP_ID_PCI_E, "PCI_CAP_ID_PCI_E"},
71a9800bebSGarrett D'Amore 	{PCI_CAP_ID_MSI_X, "PCI_CAP_ID_MSI_X"},
72a9800bebSGarrett D'Amore 	{PCI_CAP_ID_SATA, "PCI_CAP_ID_SATA"},
73a9800bebSGarrett D'Amore 	{PCI_CAP_ID_FLR, "PCI_CAP_ID_FLR"}
74a9800bebSGarrett D'Amore 
75a9800bebSGarrett D'Amore }; /* emlxs_pci_cap */
76a9800bebSGarrett D'Amore 
778f23e9faSHans Rosenfeld emlxs_table_t emlxs_pci_ecap[] = {
788f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_AER, "PCIE_EXT_CAP_ID_AER"},
798f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_VC, "PCIE_EXT_CAP_ID_VC"},
808f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_SER, "PCIE_EXT_CAP_ID_SER"},
858f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_MFVC, "PCIE_EXT_CAP_ID_MFVC"},
878f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_RCRB, "PCIE_EXT_CAP_ID_RCRB"},
888f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_VS, "PCIE_EXT_CAP_ID_VS"},
898f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_CAC, "PCIE_EXT_CAP_ID_CAC"},
908f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_ACS, "PCIE_EXT_CAP_ID_ACS"},
918f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_ARI, "PCIE_EXT_CAP_ID_ARI"},
928f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_ATS, "PCIE_EXT_CAP_ID_ATS"},
938f23e9faSHans Rosenfeld 	{PCI_EXT_CAP_ID_SRIOV, "PCI_EXT_CAP_ID_SRIOV"},
948f23e9faSHans Rosenfeld 	{PCI_EXT_CAP_ID_TPH, "PCI_EXT_CAP_ID_TPH"},
958f23e9faSHans Rosenfeld 	{PCI_EXT_CAP_ID_SEC_PCI, "PCI_EXT_CAP_ID_SEC_PCI"}
968f23e9faSHans Rosenfeld 
978f23e9faSHans Rosenfeld }; /* emlxs_pci_ecap */
988f23e9faSHans Rosenfeld 
998f23e9faSHans Rosenfeld 
10082527734SSukumar Swaminathan emlxs_table_t emlxs_ring_table[] = {
10182527734SSukumar Swaminathan 	{FC_FCP_RING, "FCP Ring"},
10282527734SSukumar Swaminathan 	{FC_IP_RING, "IP  Ring"},
10382527734SSukumar Swaminathan 	{FC_ELS_RING, "ELS Ring"},
10482527734SSukumar Swaminathan 	{FC_CT_RING, "CT  Ring"}
105291a2b48SSukumar Swaminathan 
10682527734SSukumar Swaminathan }; /* emlxs_ring_table */
107fcf3ce44SJohn Forte 
10882527734SSukumar Swaminathan emlxs_table_t emlxs_ffstate_table[] = {
10982527734SSukumar Swaminathan 	{0, "NULL"},
11082527734SSukumar Swaminathan 	{FC_ERROR, "ERROR"},
11182527734SSukumar Swaminathan 	{FC_KILLED, "KILLED"},
11282527734SSukumar Swaminathan 	{FC_WARM_START, "WARM_START"},
11382527734SSukumar Swaminathan 	{FC_INIT_START, "INIT_START"},
11482527734SSukumar Swaminathan 	{FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
11582527734SSukumar Swaminathan 	{FC_INIT_REV, "INIT_REV"},
11682527734SSukumar Swaminathan 	{FC_INIT_CFGPORT, "INIT_CFGPORT"},
11782527734SSukumar Swaminathan 	{FC_INIT_CFGRING, "INIT_CFGRING"},
11882527734SSukumar Swaminathan 	{FC_INIT_INITLINK, "INIT_INITLINK"},
11982527734SSukumar Swaminathan 	{FC_LINK_DOWN, "LINK_DOWN"},
12082527734SSukumar Swaminathan 	{FC_LINK_UP, "LINK_UP"},
12182527734SSukumar Swaminathan 	{FC_CLEAR_LA, "CLEAR_LA"},
12282527734SSukumar Swaminathan 	{FC_READY, "READY"}
123fcf3ce44SJohn Forte 
12482527734SSukumar Swaminathan }; /* emlxs_ffstate_table */
125fcf3ce44SJohn Forte 
126fcf3ce44SJohn Forte 
127fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
128fcf3ce44SJohn Forte /* EMLXS_INTR_INIT */
129fcf3ce44SJohn Forte int32_t
emlxs_msi_init(emlxs_hba_t * hba,uint32_t max)130fcf3ce44SJohn Forte emlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
131fcf3ce44SJohn Forte {
132fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
133fcf3ce44SJohn Forte 	int32_t pass = 0;
134fcf3ce44SJohn Forte 	int32_t type = 0;
135fcf3ce44SJohn Forte 	char s_type[16];
136fcf3ce44SJohn Forte 	int32_t types;
137fcf3ce44SJohn Forte 	int32_t count;
138fcf3ce44SJohn Forte 	int32_t nintrs;
139fcf3ce44SJohn Forte 	int32_t mode;
140fcf3ce44SJohn Forte 	int32_t actual;
141fcf3ce44SJohn Forte 	int32_t new_actual;
142fcf3ce44SJohn Forte 	int32_t i;
143fcf3ce44SJohn Forte 	int32_t ret;
144fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable = NULL;
145fcf3ce44SJohn Forte 	ddi_intr_handle_t *new_htable = NULL;
146fcf3ce44SJohn Forte 	uint32_t *intr_pri = NULL;
147fcf3ce44SJohn Forte 	int32_t *intr_cap = NULL;
148fcf3ce44SJohn Forte 	int32_t hilevel_pri;
149fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
150fcf3ce44SJohn Forte 
151fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
152fcf3ce44SJohn Forte 		return (emlxs_intx_init(hba, max));
153fcf3ce44SJohn Forte 	}
154291a2b48SSukumar Swaminathan 
155fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_MSI_INITED) {
156fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
157fcf3ce44SJohn Forte 	}
158291a2b48SSukumar Swaminathan 
159fcf3ce44SJohn Forte 	/* Set max interrupt count if not specified */
160fcf3ce44SJohn Forte 	if (max == 0) {
161fcf3ce44SJohn Forte 		if ((cfg[CFG_MSI_MODE].current == 2) ||
162fcf3ce44SJohn Forte 		    (cfg[CFG_MSI_MODE].current == 3)) {
163fcf3ce44SJohn Forte 			max = EMLXS_MSI_MAX_INTRS;
164fcf3ce44SJohn Forte 		} else {
165fcf3ce44SJohn Forte 			max = 1;
166fcf3ce44SJohn Forte 		}
167fcf3ce44SJohn Forte 	}
168291a2b48SSukumar Swaminathan 
169fcf3ce44SJohn Forte 	/* Filter max interrupt count with adapter model specification */
170fcf3ce44SJohn Forte 	if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
171fcf3ce44SJohn Forte 		max = hba->model_info.intr_limit;
172fcf3ce44SJohn Forte 	}
173291a2b48SSukumar Swaminathan 
174fcf3ce44SJohn Forte 	/* Get the available interrupt types from the kernel */
175fcf3ce44SJohn Forte 	types = 0;
176fcf3ce44SJohn Forte 	ret = ddi_intr_get_supported_types(hba->dip, &types);
177fcf3ce44SJohn Forte 
178fcf3ce44SJohn Forte 	if ((ret != DDI_SUCCESS)) {
179fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
180fcf3ce44SJohn Forte 		    "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
181fcf3ce44SJohn Forte 
182fcf3ce44SJohn Forte 		/* Default to fixed type */
183fcf3ce44SJohn Forte 		types = DDI_INTR_TYPE_FIXED;
184fcf3ce44SJohn Forte 	}
185291a2b48SSukumar Swaminathan 
186fcf3ce44SJohn Forte 	/* Check if fixed interrupts are being forced */
187fcf3ce44SJohn Forte 	if (cfg[CFG_MSI_MODE].current == 0) {
188fcf3ce44SJohn Forte 		types &= DDI_INTR_TYPE_FIXED;
189fcf3ce44SJohn Forte 	}
190291a2b48SSukumar Swaminathan 
191fcf3ce44SJohn Forte 	/* Check if MSI interrupts are being forced */
192fcf3ce44SJohn Forte 	else if ((cfg[CFG_MSI_MODE].current == 1) ||
193fcf3ce44SJohn Forte 	    (cfg[CFG_MSI_MODE].current == 2)) {
194fcf3ce44SJohn Forte 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
195fcf3ce44SJohn Forte 	}
196291a2b48SSukumar Swaminathan 
197fcf3ce44SJohn Forte begin:
198fcf3ce44SJohn Forte 
199fcf3ce44SJohn Forte 	/* Set interrupt type and interrupt count */
200fcf3ce44SJohn Forte 	type = 0;
201fcf3ce44SJohn Forte 
202fcf3ce44SJohn Forte 	/* Check if MSIX is fully supported */
203fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_MSIX) &&
204fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
205fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
206fcf3ce44SJohn Forte 		nintrs = 0;
207fcf3ce44SJohn Forte 		ret =
208291a2b48SSukumar Swaminathan 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX,
209291a2b48SSukumar Swaminathan 		    &nintrs);
210fcf3ce44SJohn Forte 
211fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS && nintrs) {
212fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_MSIX;
2138f23e9faSHans Rosenfeld 			(void) strlcpy(s_type, "TYPE_MSIX", sizeof (s_type));
214fcf3ce44SJohn Forte 			goto initialize;
215fcf3ce44SJohn Forte 		}
216fcf3ce44SJohn Forte 	}
217291a2b48SSukumar Swaminathan 
218fcf3ce44SJohn Forte 	/* Check if MSI is fully supported */
219fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_MSI) &&
220fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
221fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
222fcf3ce44SJohn Forte 		nintrs = 0;
223291a2b48SSukumar Swaminathan 		ret =
224291a2b48SSukumar Swaminathan 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS && nintrs) {
227fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_MSI;
2288f23e9faSHans Rosenfeld 			(void) strlcpy(s_type, "TYPE_MSI", sizeof (s_type));
229fcf3ce44SJohn Forte 			goto initialize;
230fcf3ce44SJohn Forte 		}
231fcf3ce44SJohn Forte 	}
232291a2b48SSukumar Swaminathan 
233fcf3ce44SJohn Forte 	/* Check if fixed interrupts are fully supported */
234fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_FIXED) &&
235fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
236fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
237fcf3ce44SJohn Forte 		nintrs = 0;
238fcf3ce44SJohn Forte 		ret =
239291a2b48SSukumar Swaminathan 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED,
240291a2b48SSukumar Swaminathan 		    &nintrs);
241fcf3ce44SJohn Forte 
242fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS) {
243fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_FIXED;
2448f23e9faSHans Rosenfeld 			(void) strlcpy(s_type, "TYPE_FIXED", sizeof (s_type));
245fcf3ce44SJohn Forte 			goto initialize;
246fcf3ce44SJohn Forte 		}
247fcf3ce44SJohn Forte 	}
248291a2b48SSukumar Swaminathan 
249fcf3ce44SJohn Forte 	goto init_failed;
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte initialize:
253fcf3ce44SJohn Forte 
254fcf3ce44SJohn Forte 	pass++;
255fcf3ce44SJohn Forte 	mode = 0;
256fcf3ce44SJohn Forte 	actual = 0;
257fcf3ce44SJohn Forte 	htable = NULL;
258fcf3ce44SJohn Forte 	intr_pri = NULL;
259fcf3ce44SJohn Forte 	intr_cap = NULL;
260fcf3ce44SJohn Forte 	hilevel_pri = 0;
261fcf3ce44SJohn Forte 
262fcf3ce44SJohn Forte 	if (pass == 1) {
263fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
264291a2b48SSukumar Swaminathan 		    "MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
265291a2b48SSukumar Swaminathan 		    cfg[CFG_MSI_MODE].current, types, nintrs);
266fcf3ce44SJohn Forte 	}
267291a2b48SSukumar Swaminathan 
268fcf3ce44SJohn Forte 	/* Validate interrupt count */
269fcf3ce44SJohn Forte 	count = min(nintrs, max);
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 	if (count >= 8) {
272fcf3ce44SJohn Forte 		count = 8;
273fcf3ce44SJohn Forte 	} else if (count >= 4) {
274fcf3ce44SJohn Forte 		count = 4;
275fcf3ce44SJohn Forte 	} else if (count >= 2) {
276fcf3ce44SJohn Forte 		count = 2;
277fcf3ce44SJohn Forte 	} else {
278fcf3ce44SJohn Forte 		count = 1;
279fcf3ce44SJohn Forte 	}
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 	/* Allocate an array of interrupt handles */
282fcf3ce44SJohn Forte 	htable =
283291a2b48SSukumar Swaminathan 	    kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)),
284291a2b48SSukumar Swaminathan 	    KM_SLEEP);
285fcf3ce44SJohn Forte 
286fcf3ce44SJohn Forte 	/* Allocate 'count' interrupts */
287291a2b48SSukumar Swaminathan 	ret =
288291a2b48SSukumar Swaminathan 	    ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
289fcf3ce44SJohn Forte 	    &actual, DDI_INTR_ALLOC_NORMAL);
290fcf3ce44SJohn Forte 
291fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
29282527734SSukumar Swaminathan 	    "MSI: %s: count=%d actual=%d ret=%d", s_type, count, actual, ret);
293fcf3ce44SJohn Forte 
294fcf3ce44SJohn Forte 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
295fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
296fcf3ce44SJohn Forte 		    "MSI: Unable to allocate interrupts. error=%d", ret);
297fcf3ce44SJohn Forte 
298a9800bebSGarrett D'Amore 		actual = 0;
299fcf3ce44SJohn Forte 		goto init_failed;
300fcf3ce44SJohn Forte 	}
301291a2b48SSukumar Swaminathan 
302fcf3ce44SJohn Forte 	if (actual != count) {
303fcf3ce44SJohn Forte 		/* Validate actual count */
304fcf3ce44SJohn Forte 		if (actual >= 8) {
305fcf3ce44SJohn Forte 			new_actual = 8;
306fcf3ce44SJohn Forte 		} else if (actual >= 4) {
307fcf3ce44SJohn Forte 			new_actual = 4;
308fcf3ce44SJohn Forte 		} else if (actual >= 2) {
309fcf3ce44SJohn Forte 			new_actual = 2;
310fcf3ce44SJohn Forte 		} else {
311fcf3ce44SJohn Forte 			new_actual = 1;
312fcf3ce44SJohn Forte 		}
313fcf3ce44SJohn Forte 
314fcf3ce44SJohn Forte 		if (new_actual < actual) {
315fcf3ce44SJohn Forte 			/* Free extra handles */
316fcf3ce44SJohn Forte 			for (i = new_actual; i < actual; i++) {
317fcf3ce44SJohn Forte 				(void) ddi_intr_free(htable[i]);
318fcf3ce44SJohn Forte 			}
319fcf3ce44SJohn Forte 
320fcf3ce44SJohn Forte 			actual = new_actual;
321fcf3ce44SJohn Forte 		}
322291a2b48SSukumar Swaminathan 
323fcf3ce44SJohn Forte 		/* Allocate a new array of interrupt handles */
324fcf3ce44SJohn Forte 		new_htable =
325fcf3ce44SJohn Forte 		    kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
326fcf3ce44SJohn Forte 		    KM_SLEEP);
327fcf3ce44SJohn Forte 
328fcf3ce44SJohn Forte 		/* Copy old array to new array */
329fcf3ce44SJohn Forte 		bcopy((uint8_t *)htable, (uint8_t *)new_htable,
330fcf3ce44SJohn Forte 		    (actual * sizeof (ddi_intr_handle_t)));
331fcf3ce44SJohn Forte 
332fcf3ce44SJohn Forte 		/* Free the old array */
333fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
334fcf3ce44SJohn Forte 
335fcf3ce44SJohn Forte 		htable = new_htable;
336fcf3ce44SJohn Forte 		count = actual;
337fcf3ce44SJohn Forte 	}
338291a2b48SSukumar Swaminathan 
339fcf3ce44SJohn Forte 	/* Allocate interrupt priority table */
340fcf3ce44SJohn Forte 	intr_pri =
341fcf3ce44SJohn Forte 	    (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
342fcf3ce44SJohn Forte 	    KM_SLEEP);
343fcf3ce44SJohn Forte 
344fcf3ce44SJohn Forte 	/* Allocate interrupt capability table */
345fcf3ce44SJohn Forte 	intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
346fcf3ce44SJohn Forte 
347fcf3ce44SJohn Forte 	/* Get minimum hilevel priority */
348fcf3ce44SJohn Forte 	hilevel_pri = ddi_intr_get_hilevel_pri();
349fcf3ce44SJohn Forte 
350fcf3ce44SJohn Forte 	/* Fill the priority and capability tables */
351fcf3ce44SJohn Forte 	for (i = 0; i < count; ++i) {
352fcf3ce44SJohn Forte 		ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
355fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
356fcf3ce44SJohn Forte 			    "MSI: ddi_intr_get_pri(%d) failed. "
357291a2b48SSukumar Swaminathan 			    "handle=%p ret=%d",
358291a2b48SSukumar Swaminathan 			    i, &htable[i], ret);
359fcf3ce44SJohn Forte 
360fcf3ce44SJohn Forte 			/* Clean up the interrupts */
361fcf3ce44SJohn Forte 			goto init_failed;
362fcf3ce44SJohn Forte 		}
363291a2b48SSukumar Swaminathan 
364fcf3ce44SJohn Forte 		if (intr_pri[i] >= hilevel_pri) {
365fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
366fcf3ce44SJohn Forte 			    "MSI: Interrupt(%d) level too high. "
367fcf3ce44SJohn Forte 			    "pri=0x%x hilevel=0x%x",
368fcf3ce44SJohn Forte 			    i, intr_pri[i], hilevel_pri);
369fcf3ce44SJohn Forte 
370fcf3ce44SJohn Forte 			/* Clean up the interrupts */
371fcf3ce44SJohn Forte 			goto init_failed;
372fcf3ce44SJohn Forte 		}
373291a2b48SSukumar Swaminathan 
374fcf3ce44SJohn Forte 		ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
377fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
378291a2b48SSukumar Swaminathan 			    "MSI: ddi_intr_get_cap(%d) failed. "
379291a2b48SSukumar Swaminathan 			    "handle=%p ret=%d",
380291a2b48SSukumar Swaminathan 			    i, &htable[i], ret);
381fcf3ce44SJohn Forte 
382fcf3ce44SJohn Forte 			/* Clean up the interrupts */
383fcf3ce44SJohn Forte 			goto init_failed;
384fcf3ce44SJohn Forte 		}
385291a2b48SSukumar Swaminathan 
386fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
387291a2b48SSukumar Swaminathan 		    "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
388291a2b48SSukumar Swaminathan 		    intr_cap[i], intr_pri[i], hilevel_pri);
389fcf3ce44SJohn Forte 
390fcf3ce44SJohn Forte 	}
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte 	/* Set mode */
393fcf3ce44SJohn Forte 	switch (count) {
394fcf3ce44SJohn Forte 	case 8:
395fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE8;
396fcf3ce44SJohn Forte 		break;
397fcf3ce44SJohn Forte 
398fcf3ce44SJohn Forte 	case 4:
399fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE4;
400fcf3ce44SJohn Forte 		break;
401fcf3ce44SJohn Forte 
402fcf3ce44SJohn Forte 	case 2:
403fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE2;
404fcf3ce44SJohn Forte 		break;
405fcf3ce44SJohn Forte 
406fcf3ce44SJohn Forte 	default:
407fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE1;
408fcf3ce44SJohn Forte 	}
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 	/* Save the info */
411fcf3ce44SJohn Forte 	hba->intr_htable = htable;
412fcf3ce44SJohn Forte 	hba->intr_count = count;
413fcf3ce44SJohn Forte 	hba->intr_pri = intr_pri;
414fcf3ce44SJohn Forte 	hba->intr_cap = intr_cap;
415fcf3ce44SJohn Forte 	hba->intr_type = type;
416291a2b48SSukumar Swaminathan 	hba->intr_arg = (void *)((unsigned long)intr_pri[0]);
417fcf3ce44SJohn Forte 	hba->intr_mask = emlxs_msi_mask[mode];
418fcf3ce44SJohn Forte 
419fcf3ce44SJohn Forte 	hba->intr_cond = 0;
42082527734SSukumar Swaminathan 
42182527734SSukumar Swaminathan 	/* Adjust number of channels based on intr_count */
42282527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
42382527734SSukumar Swaminathan 		hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
42482527734SSukumar Swaminathan 	}
42582527734SSukumar Swaminathan 
426fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
427fcf3ce44SJohn Forte 		hba->intr_map[i] = emlxs_msi_map[mode][i];
428fcf3ce44SJohn Forte 		hba->intr_cond |= emlxs_msi_map[mode][i];
429fcf3ce44SJohn Forte 
4308f23e9faSHans Rosenfeld 		mutex_init(&hba->intr_lock[i], NULL, MUTEX_DRIVER,
431a9800bebSGarrett D'Amore 		    DDI_INTR_PRI(hba->intr_arg));
432fcf3ce44SJohn Forte 	}
433fcf3ce44SJohn Forte 
434fcf3ce44SJohn Forte 	/* Set flag to indicate support */
435fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_MSI_INITED;
436fcf3ce44SJohn Forte 
437fcf3ce44SJohn Forte 	/* Create the interrupt threads */
43882527734SSukumar Swaminathan 	for (i = 0; i < hba->chan_count; i++) {
4398f23e9faSHans Rosenfeld 		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
440a9800bebSGarrett D'Amore 		    DDI_INTR_PRI(hba->intr_arg));
441fcf3ce44SJohn Forte 
44282527734SSukumar Swaminathan 		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
443fcf3ce44SJohn Forte 	}
444fcf3ce44SJohn Forte 
445fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
446fcf3ce44SJohn Forte 
447fcf3ce44SJohn Forte init_failed:
448fcf3ce44SJohn Forte 
449fcf3ce44SJohn Forte 	if (intr_cap) {
450fcf3ce44SJohn Forte 		kmem_free(intr_cap, (count * sizeof (int32_t)));
451fcf3ce44SJohn Forte 	}
452291a2b48SSukumar Swaminathan 
453fcf3ce44SJohn Forte 	if (intr_pri) {
454fcf3ce44SJohn Forte 		kmem_free(intr_pri, (count * sizeof (int32_t)));
455fcf3ce44SJohn Forte 	}
456291a2b48SSukumar Swaminathan 
457fcf3ce44SJohn Forte 	if (htable) {
458fcf3ce44SJohn Forte 		/* Process the interrupt handlers */
459fcf3ce44SJohn Forte 		for (i = 0; i < actual; i++) {
460fcf3ce44SJohn Forte 			/* Free the handle[i] */
461fcf3ce44SJohn Forte 			(void) ddi_intr_free(htable[i]);
462fcf3ce44SJohn Forte 		}
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
465fcf3ce44SJohn Forte 	}
466291a2b48SSukumar Swaminathan 
467fcf3ce44SJohn Forte 	/* Initialize */
468fcf3ce44SJohn Forte 	hba->intr_htable = NULL;
469fcf3ce44SJohn Forte 	hba->intr_count = 0;
470fcf3ce44SJohn Forte 	hba->intr_pri = NULL;
471fcf3ce44SJohn Forte 	hba->intr_cap = NULL;
472fcf3ce44SJohn Forte 	hba->intr_type = 0;
473fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
474fcf3ce44SJohn Forte 	hba->intr_cond = 0;
475fcf3ce44SJohn Forte 	bzero(hba->intr_map, sizeof (hba->intr_map));
476fcf3ce44SJohn Forte 	bzero(hba->intr_lock, sizeof (hba->intr_lock));
477fcf3ce44SJohn Forte 
478fcf3ce44SJohn Forte 	if (type == DDI_INTR_TYPE_MSIX) {
479fcf3ce44SJohn Forte 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
480fcf3ce44SJohn Forte 		goto begin;
481fcf3ce44SJohn Forte 	} else if (type == DDI_INTR_TYPE_MSI) {
482fcf3ce44SJohn Forte 		types &= DDI_INTR_TYPE_FIXED;
483fcf3ce44SJohn Forte 		goto begin;
484fcf3ce44SJohn Forte 	}
485291a2b48SSukumar Swaminathan 
486fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
487fcf3ce44SJohn Forte 	    "MSI: Unable to initialize interrupts");
488fcf3ce44SJohn Forte 
489fcf3ce44SJohn Forte 	return (DDI_FAILURE);
490fcf3ce44SJohn Forte 
491fcf3ce44SJohn Forte 
49282527734SSukumar Swaminathan } /* emlxs_msi_init() */
493fcf3ce44SJohn Forte 
494fcf3ce44SJohn Forte 
495fcf3ce44SJohn Forte /* EMLXS_INTR_UNINIT */
496fcf3ce44SJohn Forte int32_t
emlxs_msi_uninit(emlxs_hba_t * hba)497fcf3ce44SJohn Forte emlxs_msi_uninit(emlxs_hba_t *hba)
498fcf3ce44SJohn Forte {
499fcf3ce44SJohn Forte 	uint32_t count;
500fcf3ce44SJohn Forte 	int32_t i;
501fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable;
502fcf3ce44SJohn Forte 	uint32_t *intr_pri;
503fcf3ce44SJohn Forte 	int32_t *intr_cap;
504fcf3ce44SJohn Forte 	int32_t ret;
505fcf3ce44SJohn Forte 
506fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
507fcf3ce44SJohn Forte 		return (emlxs_intx_uninit(hba));
508fcf3ce44SJohn Forte 	}
509291a2b48SSukumar Swaminathan 
510fcf3ce44SJohn Forte 	/*
511291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5128f23e9faSHans Rosenfeld 	 *    "MSI: msi_uninit called. flags=%x",
513291a2b48SSukumar Swaminathan 	 *    hba->intr_flags);
514fcf3ce44SJohn Forte 	 */
515fcf3ce44SJohn Forte 
516fcf3ce44SJohn Forte 	/* Make sure interrupts have been removed first */
517fcf3ce44SJohn Forte 	if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
518fcf3ce44SJohn Forte 		ret = emlxs_msi_remove(hba);
519fcf3ce44SJohn Forte 
520fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
521fcf3ce44SJohn Forte 			return (ret);
522fcf3ce44SJohn Forte 		}
523fcf3ce44SJohn Forte 	}
524291a2b48SSukumar Swaminathan 
525fcf3ce44SJohn Forte 	/* Check if the interrupts are still initialized */
526fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
527fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
528fcf3ce44SJohn Forte 	}
529fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_MSI_INITED;
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	/* Get handle table parameters */
532fcf3ce44SJohn Forte 	htable = hba->intr_htable;
533fcf3ce44SJohn Forte 	count = hba->intr_count;
534fcf3ce44SJohn Forte 	intr_pri = hba->intr_pri;
535fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte 	/* Clean up */
538fcf3ce44SJohn Forte 	hba->intr_count = 0;
539fcf3ce44SJohn Forte 	hba->intr_htable = NULL;
540fcf3ce44SJohn Forte 	hba->intr_pri = NULL;
541fcf3ce44SJohn Forte 	hba->intr_cap = NULL;
542fcf3ce44SJohn Forte 	hba->intr_type = 0;
543fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
544fcf3ce44SJohn Forte 	hba->intr_cond = 0;
545fcf3ce44SJohn Forte 	bzero(hba->intr_map, sizeof (hba->intr_map));
546fcf3ce44SJohn Forte 
547fcf3ce44SJohn Forte 	if (intr_cap) {
548fcf3ce44SJohn Forte 		kmem_free(intr_cap, (count * sizeof (int32_t)));
549fcf3ce44SJohn Forte 	}
550291a2b48SSukumar Swaminathan 
551fcf3ce44SJohn Forte 	if (intr_pri) {
552fcf3ce44SJohn Forte 		kmem_free(intr_pri, (count * sizeof (int32_t)));
553fcf3ce44SJohn Forte 	}
554291a2b48SSukumar Swaminathan 
555fcf3ce44SJohn Forte 	if (htable) {
556fcf3ce44SJohn Forte 		/* Process the interrupt handlers */
557fcf3ce44SJohn Forte 		for (i = 0; i < count; ++i) {
558fcf3ce44SJohn Forte 			/* Free the handle[i] */
559291a2b48SSukumar Swaminathan 			ret = ddi_intr_free(htable[i]);
560fcf3ce44SJohn Forte 		}
561fcf3ce44SJohn Forte 
562fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
563fcf3ce44SJohn Forte 	}
564291a2b48SSukumar Swaminathan 
565fcf3ce44SJohn Forte 	/* Destroy the intr locks */
566fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
567fcf3ce44SJohn Forte 		mutex_destroy(&hba->intr_lock[i]);
568fcf3ce44SJohn Forte 	}
569fcf3ce44SJohn Forte 
570fcf3ce44SJohn Forte 	/* Destroy the interrupt threads */
57182527734SSukumar Swaminathan 	for (i = 0; i < hba->chan_count; i++) {
57282527734SSukumar Swaminathan 		emlxs_thread_destroy(&hba->chan[i].intr_thread);
57382527734SSukumar Swaminathan 		mutex_destroy(&hba->chan[i].rsp_lock);
574fcf3ce44SJohn Forte 	}
575fcf3ce44SJohn Forte 
576fcf3ce44SJohn Forte 	/*
577291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5788f23e9faSHans Rosenfeld 	 *    "MSI: msi_uninit done. flags=%x",
579291a2b48SSukumar Swaminathan 	 *    hba->intr_flags);
580fcf3ce44SJohn Forte 	 */
581fcf3ce44SJohn Forte 
582fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
583fcf3ce44SJohn Forte 
58482527734SSukumar Swaminathan } /* emlxs_msi_uninit() */
585fcf3ce44SJohn Forte 
586fcf3ce44SJohn Forte 
587fcf3ce44SJohn Forte /* EMLXS_INTR_ADD */
588fcf3ce44SJohn Forte int32_t
emlxs_msi_add(emlxs_hba_t * hba)589fcf3ce44SJohn Forte emlxs_msi_add(emlxs_hba_t *hba)
590fcf3ce44SJohn Forte {
591fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
592fcf3ce44SJohn Forte 	int32_t count;
593fcf3ce44SJohn Forte 	int32_t i;
594fcf3ce44SJohn Forte 	int32_t ret;
595fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable = NULL;
596fcf3ce44SJohn Forte 	int32_t *intr_cap = NULL;
597fcf3ce44SJohn Forte 
598fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
599fcf3ce44SJohn Forte 		return (emlxs_intx_add(hba));
600fcf3ce44SJohn Forte 	}
601291a2b48SSukumar Swaminathan 
602fcf3ce44SJohn Forte 	/* Check if interrupts have already been added */
603fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_MSI_ADDED) {
604fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
605fcf3ce44SJohn Forte 	}
606291a2b48SSukumar Swaminathan 
607fcf3ce44SJohn Forte 	/* Check if interrupts have been initialized */
608fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
609fcf3ce44SJohn Forte 		ret = emlxs_msi_init(hba, 0);
610fcf3ce44SJohn Forte 
611fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
612fcf3ce44SJohn Forte 			return (ret);
613fcf3ce44SJohn Forte 		}
614fcf3ce44SJohn Forte 	}
615291a2b48SSukumar Swaminathan 
616fcf3ce44SJohn Forte 	/* Get handle table parameters */
617fcf3ce44SJohn Forte 	htable = hba->intr_htable;
618fcf3ce44SJohn Forte 	count = hba->intr_count;
619fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
620fcf3ce44SJohn Forte 
621fcf3ce44SJohn Forte 	/* Add the interrupt handlers */
622fcf3ce44SJohn Forte 	for (i = 0; i < count; ++i) {
623fcf3ce44SJohn Forte 		/* add handler for handle[i] */
624291a2b48SSukumar Swaminathan 		ret =
62582527734SSukumar Swaminathan 		    ddi_intr_add_handler(htable[i], EMLXS_SLI_MSI_INTR,
626291a2b48SSukumar Swaminathan 		    (char *)hba, (char *)((unsigned long)i));
627fcf3ce44SJohn Forte 
628fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
629fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
630291a2b48SSukumar Swaminathan 			    "MSI: ddi_intr_add_handler(%d) failed. "
631291a2b48SSukumar Swaminathan 			    "handle=%p ret=%d",
632291a2b48SSukumar Swaminathan 			    i, &htable[i], ret);
633fcf3ce44SJohn Forte 
634fcf3ce44SJohn Forte 			/* Process the remaining interrupt handlers */
635fcf3ce44SJohn Forte 			while (i) {
636fcf3ce44SJohn Forte 				/* Decrement i */
637fcf3ce44SJohn Forte 				i--;
638fcf3ce44SJohn Forte 
639fcf3ce44SJohn Forte 				/* Remove the handler */
640fcf3ce44SJohn Forte 				ret = ddi_intr_remove_handler(htable[i]);
641fcf3ce44SJohn Forte 
642fcf3ce44SJohn Forte 			}
643fcf3ce44SJohn Forte 
644fcf3ce44SJohn Forte 			return (DDI_FAILURE);
645fcf3ce44SJohn Forte 		}
646fcf3ce44SJohn Forte 	}
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 	/* Enable the interrupts */
649fcf3ce44SJohn Forte 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
650fcf3ce44SJohn Forte 		ret = ddi_intr_block_enable(htable, count);
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
653fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
654fcf3ce44SJohn Forte 			    "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
655fcf3ce44SJohn Forte 			    count, ret);
656fcf3ce44SJohn Forte 
657fcf3ce44SJohn Forte 			for (i = 0; i < count; ++i) {
658fcf3ce44SJohn Forte 				ret = ddi_intr_enable(htable[i]);
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 				if (ret != DDI_SUCCESS) {
661fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
662fcf3ce44SJohn Forte 					    &emlxs_init_debug_msg,
663fcf3ce44SJohn Forte 					    "MSI: ddi_intr_enable(%d) failed. "
664291a2b48SSukumar Swaminathan 					    "ret=%d",
665291a2b48SSukumar Swaminathan 					    i, ret);
666fcf3ce44SJohn Forte 				}
667fcf3ce44SJohn Forte 			}
668fcf3ce44SJohn Forte 		}
669fcf3ce44SJohn Forte 	} else {
670fcf3ce44SJohn Forte 		for (i = 0; i < count; ++i) {
671fcf3ce44SJohn Forte 			ret = ddi_intr_enable(htable[i]);
672fcf3ce44SJohn Forte 
673fcf3ce44SJohn Forte 			if (ret != DDI_SUCCESS) {
674291a2b48SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
675291a2b48SSukumar Swaminathan 				    &emlxs_init_debug_msg,
676fcf3ce44SJohn Forte 				    "MSI: ddi_intr_enable(%d) failed. ret=%d",
677fcf3ce44SJohn Forte 				    i, ret);
678fcf3ce44SJohn Forte 			}
679fcf3ce44SJohn Forte 		}
680fcf3ce44SJohn Forte 	}
681fcf3ce44SJohn Forte 
682fcf3ce44SJohn Forte 
683fcf3ce44SJohn Forte 	/* Set flag to indicate support */
684fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_MSI_ADDED;
685fcf3ce44SJohn Forte 
686fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
687fcf3ce44SJohn Forte 
68882527734SSukumar Swaminathan } /* emlxs_msi_add() */
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 
691fcf3ce44SJohn Forte 
692fcf3ce44SJohn Forte /* EMLXS_INTR_REMOVE */
693fcf3ce44SJohn Forte int32_t
emlxs_msi_remove(emlxs_hba_t * hba)694fcf3ce44SJohn Forte emlxs_msi_remove(emlxs_hba_t *hba)
695fcf3ce44SJohn Forte {
696fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
697fcf3ce44SJohn Forte 	uint32_t count;
698fcf3ce44SJohn Forte 	int32_t i;
699fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable;
700fcf3ce44SJohn Forte 	int32_t *intr_cap;
701fcf3ce44SJohn Forte 	int32_t ret;
702fcf3ce44SJohn Forte 
703fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
704fcf3ce44SJohn Forte 		return (emlxs_intx_remove(hba));
705fcf3ce44SJohn Forte 	}
706291a2b48SSukumar Swaminathan 
707fcf3ce44SJohn Forte 	/*
708291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
7098f23e9faSHans Rosenfeld 	 *    "MSI: msi_remove called. flags=%x",
710291a2b48SSukumar Swaminathan 	 *    hba->intr_flags);
711fcf3ce44SJohn Forte 	 */
712fcf3ce44SJohn Forte 
713fcf3ce44SJohn Forte 	/* Check if interrupts have already been removed */
714fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
715fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
716fcf3ce44SJohn Forte 	}
717fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_MSI_ADDED;
718fcf3ce44SJohn Forte 
719fcf3ce44SJohn Forte 	/* Disable all adapter interrupts */
72082527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
721fcf3ce44SJohn Forte 
722fcf3ce44SJohn Forte 	/* Get handle table parameters */
723fcf3ce44SJohn Forte 	htable = hba->intr_htable;
724fcf3ce44SJohn Forte 	count = hba->intr_count;
725fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
726fcf3ce44SJohn Forte 
727fcf3ce44SJohn Forte 	/* Disable the interrupts */
728fcf3ce44SJohn Forte 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
729fcf3ce44SJohn Forte 		ret = ddi_intr_block_disable(htable, count);
730fcf3ce44SJohn Forte 
731fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
732fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
733fcf3ce44SJohn Forte 			    "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
734fcf3ce44SJohn Forte 			    count, ret);
735fcf3ce44SJohn Forte 
736fcf3ce44SJohn Forte 			for (i = 0; i < count; i++) {
737fcf3ce44SJohn Forte 				ret = ddi_intr_disable(htable[i]);
738fcf3ce44SJohn Forte 
739fcf3ce44SJohn Forte 				if (ret != DDI_SUCCESS) {
740fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
741fcf3ce44SJohn Forte 					    &emlxs_init_debug_msg,
742fcf3ce44SJohn Forte 					    "MSI: ddi_intr_disable(%d) failed. "
743291a2b48SSukumar Swaminathan 					    "ret=%d",
744291a2b48SSukumar Swaminathan 					    i, ret);
745fcf3ce44SJohn Forte 				}
746fcf3ce44SJohn Forte 			}
747fcf3ce44SJohn Forte 		}
748fcf3ce44SJohn Forte 	} else {
749fcf3ce44SJohn Forte 		for (i = 0; i < count; i++) {
750fcf3ce44SJohn Forte 			ret = ddi_intr_disable(htable[i]);
751fcf3ce44SJohn Forte 
752fcf3ce44SJohn Forte 			if (ret != DDI_SUCCESS) {
753291a2b48SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
754291a2b48SSukumar Swaminathan 				    &emlxs_init_debug_msg,
755fcf3ce44SJohn Forte 				    "MSI: ddi_intr_disable(%d) failed. ret=%d",
756fcf3ce44SJohn Forte 				    i, ret);
757fcf3ce44SJohn Forte 			}
758fcf3ce44SJohn Forte 		}
759fcf3ce44SJohn Forte 	}
760fcf3ce44SJohn Forte 
761fcf3ce44SJohn Forte 	/* Process the interrupt handlers */
762fcf3ce44SJohn Forte 	for (i = 0; i < count; i++) {
763fcf3ce44SJohn Forte 		/* Remove the handler */
764fcf3ce44SJohn Forte 		ret = ddi_intr_remove_handler(htable[i]);
765fcf3ce44SJohn Forte 
766fcf3ce44SJohn Forte 
767fcf3ce44SJohn Forte 	}
768fcf3ce44SJohn Forte 
769fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
770fcf3ce44SJohn Forte 
77182527734SSukumar Swaminathan } /* emlxs_msi_remove() */
772fcf3ce44SJohn Forte 
773291a2b48SSukumar Swaminathan #endif /* MSI_SUPPORT */
774fcf3ce44SJohn Forte 
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte /* EMLXS_INTR_INIT */
777fcf3ce44SJohn Forte /* ARGSUSED */
778fcf3ce44SJohn Forte int32_t
emlxs_intx_init(emlxs_hba_t * hba,uint32_t max)779fcf3ce44SJohn Forte emlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
780fcf3ce44SJohn Forte {
781fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
78282527734SSukumar Swaminathan 	emlxs_config_t *cfg = &CFG;
783fcf3ce44SJohn Forte 	int32_t ret;
784fcf3ce44SJohn Forte 	uint32_t i;
785fcf3ce44SJohn Forte 
786fcf3ce44SJohn Forte 	/* Check if interrupts have already been initialized */
787fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_INTX_INITED) {
788fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
789fcf3ce44SJohn Forte 	}
790291a2b48SSukumar Swaminathan 
791fcf3ce44SJohn Forte 	/* Check if adapter is flagged for INTX support */
792fcf3ce44SJohn Forte 	if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
793fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
794fcf3ce44SJohn Forte 		    "INTX: %s does not support INTX.  flags=0x%x",
795fcf3ce44SJohn Forte 		    hba->model_info.model, hba->model_info.flags);
796fcf3ce44SJohn Forte 
797fcf3ce44SJohn Forte 		return (DDI_FAILURE);
798fcf3ce44SJohn Forte 	}
799291a2b48SSukumar Swaminathan 
800fcf3ce44SJohn Forte 	/*
801291a2b48SSukumar Swaminathan 	 * Interrupt number '0' is a high-level interrupt. This driver
802291a2b48SSukumar Swaminathan 	 * does not support having its interrupts mapped above scheduler
803291a2b48SSukumar Swaminathan 	 * priority; i.e., we always expect to be able to call general
804291a2b48SSukumar Swaminathan 	 * kernel routines that may invoke the scheduler.
805fcf3ce44SJohn Forte 	 */
806fcf3ce44SJohn Forte 	if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
807fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
808fcf3ce44SJohn Forte 		    "INTX: High-level interrupt not supported.");
809fcf3ce44SJohn Forte