1fcf3ce4John Forte/*
2fcf3ce4John Forte * CDDL HEADER START
3fcf3ce4John Forte *
4fcf3ce4John Forte * The contents of this file are subject to the terms of the
5fcf3ce4John Forte * Common Development and Distribution License (the "License").
6fcf3ce4John Forte * You may not use this file except in compliance with the License.
7fcf3ce4John Forte *
88f23e9fHans Rosenfeld * You can obtain a copy of the license at
98f23e9fHans Rosenfeld * http://www.opensource.org/licenses/cddl1.txt.
10fcf3ce4John Forte * See the License for the specific language governing permissions
11fcf3ce4John Forte * and limitations under the License.
12fcf3ce4John Forte *
13fcf3ce4John Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce4John Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce4John Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce4John Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce4John Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce4John Forte *
19fcf3ce4John Forte * CDDL HEADER END
20fcf3ce4John Forte */
21fcf3ce4John Forte
22fcf3ce4John Forte/*
238f23e9fHans Rosenfeld * Copyright (c) 2004-2012 Emulex. All rights reserved.
248252773Sukumar Swaminathan * Use is subject to license terms.
25a317005Paul Winder * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26a317005Paul Winder * Copyright 2020 RackTop Systems, Inc.
27fcf3ce4John Forte */
28fcf3ce4John Forte
298252773Sukumar Swaminathan#define	EMLXS_FW_TABLE_DEF
308252773Sukumar Swaminathan#define	EMLXS_MODEL_DEF
31fcf3ce4John Forte
328252773Sukumar Swaminathan#include <emlxs.h>
33fcf3ce4John Forte
348252773Sukumar Swaminathan/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
358252773Sukumar SwaminathanEMLXS_MSG_DEF(EMLXS_HBA_C);
36fcf3ce4John Forte
37a9800beGarrett D'Amore
388252773Sukumar Swaminathanstatic void emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp,
398252773Sukumar Swaminathan    IOCBQ *iocbq);
40291a2b4Sukumar Swaminathan
41a9800beGarrett D'Amorestatic void emlxs_pci_cap_offsets(emlxs_hba_t *hba);
42a9800beGarrett D'Amore
43fcf3ce4John Forte#ifdef MSI_SUPPORT
448252773Sukumar Swaminathanuint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
458252773Sukumar Swaminathan	{EMLXS_MSI_MAP1, EMLXS_MSI_MAP2, EMLXS_MSI_MAP4, EMLXS_MSI_MAP8};
468252773Sukumar Swaminathanuint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
478252773Sukumar Swaminathan	{EMLXS_MSI0_MASK1, EMLXS_MSI0_MASK2, EMLXS_MSI0_MASK4,
488252773Sukumar Swaminathan	EMLXS_MSI0_MASK8};
49291a2b4Sukumar Swaminathan#endif /* MSI_SUPPORT */
50fcf3ce4John Forte
518252773Sukumar Swaminathanemlxs_firmware_t emlxs_fw_table[] = EMLXS_FW_TABLE;
528252773Sukumar Swaminathanint emlxs_fw_count = sizeof (emlxs_fw_table) / sizeof (emlxs_firmware_t);
53291a2b4Sukumar Swaminathan
54a9800beGarrett D'Amoreemlxs_table_t emlxs_pci_cap[] = {
55a9800beGarrett D'Amore	{PCI_CAP_ID_PM, "PCI_CAP_ID_PM"},
56a9800beGarrett D'Amore	{PCI_CAP_ID_AGP, "PCI_CAP_ID_AGP"},
57a9800beGarrett D'Amore	{PCI_CAP_ID_VPD, "PCI_CAP_ID_VPD"},
58a9800beGarrett D'Amore	{PCI_CAP_ID_SLOT_ID, "PCI_CAP_ID_SLOT_ID"},
59a9800beGarrett D'Amore	{PCI_CAP_ID_MSI, "PCI_CAP_ID_MSI"},
60a9800beGarrett D'Amore	{PCI_CAP_ID_cPCI_HS, "PCI_CAP_ID_cPCI_HS"},
61a9800beGarrett D'Amore	{PCI_CAP_ID_PCIX, "PCI_CAP_ID_PCIX"},
62a9800beGarrett D'Amore	{PCI_CAP_ID_HT, "PCI_CAP_ID_HT"},
63a9800beGarrett D'Amore	{PCI_CAP_ID_VS, "PCI_CAP_ID_VS"},
64a9800beGarrett D'Amore	{PCI_CAP_ID_DEBUG_PORT, "PCI_CAP_ID_DEBUG_PORT"},
65a9800beGarrett D'Amore	{PCI_CAP_ID_cPCI_CRC, "PCI_CAP_ID_cPCI_CRC"},
66a9800beGarrett D'Amore	{PCI_CAP_ID_PCI_HOTPLUG, "PCI_CAP_ID_PCI_HOTPLUG"},
67a9800beGarrett D'Amore	{PCI_CAP_ID_P2P_SUBSYS, "PCI_CAP_ID_P2P_SUBSYS"},
68a9800beGarrett D'Amore	{PCI_CAP_ID_AGP_8X, "PCI_CAP_ID_AGP_8X"},
69a9800beGarrett D'Amore	{PCI_CAP_ID_SECURE_DEV, "PCI_CAP_ID_SECURE_DEV"},
70a9800beGarrett D'Amore	{PCI_CAP_ID_PCI_E, "PCI_CAP_ID_PCI_E"},
71a9800beGarrett D'Amore	{PCI_CAP_ID_MSI_X, "PCI_CAP_ID_MSI_X"},
72a9800beGarrett D'Amore	{PCI_CAP_ID_SATA, "PCI_CAP_ID_SATA"},
73a9800beGarrett D'Amore	{PCI_CAP_ID_FLR, "PCI_CAP_ID_FLR"}
74a9800beGarrett D'Amore
75a9800beGarrett D'Amore}; /* emlxs_pci_cap */
76a9800beGarrett D'Amore
778f23e9fHans Rosenfeldemlxs_table_t emlxs_pci_ecap[] = {
788f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_AER, "PCIE_EXT_CAP_ID_AER"},
798f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_VC, "PCIE_EXT_CAP_ID_VC"},
808f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_SER, "PCIE_EXT_CAP_ID_SER"},
818f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_PWR_BUDGET, "PCIE_EXT_CAP_ID_PWR_BUDGET"},
828f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_RC_LINK_DECL, "PCIE_EXT_CAP_ID_RC_LINK_DECL"},
838f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "PCIE_EXT_CAP_ID_RC_INT_LINKCTRL"},
848f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_RC_EVNT_CEA, "PCIE_EXT_CAP_ID_RC_EVNT_CEA"},
858f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_MFVC, "PCIE_EXT_CAP_ID_MFVC"},
868f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_VC_WITH_MFVC, "PCIE_EXT_CAP_ID_VC_WITH_MFVC"},
878f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_RCRB, "PCIE_EXT_CAP_ID_RCRB"},
888f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_VS, "PCIE_EXT_CAP_ID_VS"},
898f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_CAC, "PCIE_EXT_CAP_ID_CAC"},
908f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_ACS, "PCIE_EXT_CAP_ID_ACS"},
918f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_ARI, "PCIE_EXT_CAP_ID_ARI"},
928f23e9fHans Rosenfeld	{PCIE_EXT_CAP_ID_ATS, "PCIE_EXT_CAP_ID_ATS"},
938f23e9fHans Rosenfeld	{PCI_EXT_CAP_ID_SRIOV, "PCI_EXT_CAP_ID_SRIOV"},
948f23e9fHans Rosenfeld	{PCI_EXT_CAP_ID_TPH, "PCI_EXT_CAP_ID_TPH"},
958f23e9fHans Rosenfeld	{PCI_EXT_CAP_ID_SEC_PCI, "PCI_EXT_CAP_ID_SEC_PCI"}
968f23e9fHans Rosenfeld
978f23e9fHans Rosenfeld}; /* emlxs_pci_ecap */
988f23e9fHans Rosenfeld
998f23e9fHans Rosenfeld
1008252773Sukumar Swaminathanemlxs_table_t emlxs_ring_table[] = {
1018252773Sukumar Swaminathan	{FC_FCP_RING, "FCP Ring"},
1028252773Sukumar Swaminathan	{FC_IP_RING, "IP  Ring"},
1038252773Sukumar Swaminathan	{FC_ELS_RING, "ELS Ring"},
1048252773Sukumar Swaminathan	{FC_CT_RING, "CT  Ring"}
105291a2b4Sukumar Swaminathan
1068252773Sukumar Swaminathan}; /* emlxs_ring_table */
107fcf3ce4John Forte
1088252773Sukumar Swaminathanemlxs_table_t emlxs_ffstate_table[] = {
1098252773Sukumar Swaminathan	{0, "NULL"},
1108252773Sukumar Swaminathan	{FC_ERROR, "ERROR"},
1118252773Sukumar Swaminathan	{FC_KILLED, "KILLED"},
1128252773Sukumar Swaminathan	{FC_WARM_START, "WARM_START"},
1138252773Sukumar Swaminathan	{FC_INIT_START, "INIT_START"},
1148252773Sukumar Swaminathan	{FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
1158252773Sukumar Swaminathan	{FC_INIT_REV, "INIT_REV"},
1168252773Sukumar Swaminathan	{FC_INIT_CFGPORT, "INIT_CFGPORT"},
1178252773Sukumar Swaminathan	{FC_INIT_CFGRING, "INIT_CFGRING"},
1188252773Sukumar Swaminathan	{FC_INIT_INITLINK, "INIT_INITLINK"},
1198252773Sukumar Swaminathan	{FC_LINK_DOWN, "LINK_DOWN"},
1208252773Sukumar Swaminathan	{FC_LINK_UP, "LINK_UP"},
1218252773Sukumar Swaminathan	{FC_CLEAR_LA, "CLEAR_LA"},
1228252773Sukumar Swaminathan	{FC_READY, "READY"}
123fcf3ce4John Forte
1248252773Sukumar Swaminathan}; /* emlxs_ffstate_table */
125fcf3ce4John Forte
126fcf3ce4John Forte
127fcf3ce4John Forte#ifdef MSI_SUPPORT
128fcf3ce4John Forte/* EMLXS_INTR_INIT */
129fcf3ce4John Forteint32_t
130fcf3ce4John Forteemlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
131fcf3ce4John Forte{
132fcf3ce4John Forte	emlxs_port_t *port = &PPORT;
133fcf3ce4John Forte	int32_t pass = 0;
134fcf3ce4John Forte	int32_t type = 0;
135fcf3ce4John Forte	char s_type[16];
136fcf3ce4John Forte	int32_t types;
137fcf3ce4John Forte	int32_t count;
138fcf3ce4John Forte	int32_t nintrs;
139fcf3ce4John Forte	int32_t mode;
140fcf3ce4John Forte	int32_t actual;
141fcf3ce4John Forte	int32_t new_actual;
142fcf3ce4John Forte	int32_t i;
143fcf3ce4John Forte	int32_t ret;
144fcf3ce4John Forte	ddi_intr_handle_t *htable = NULL;
145fcf3ce4John Forte	ddi_intr_handle_t *new_htable = NULL;
146fcf3ce4John Forte	uint32_t *intr_pri = NULL;
147fcf3ce4John Forte	int32_t *intr_cap = NULL;
148fcf3ce4John Forte	int32_t hilevel_pri;
149fcf3ce4John Forte	emlxs_config_t *cfg = &CFG;
150fcf3ce4John Forte
151fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
152fcf3ce4John Forte		return (emlxs_intx_init(hba, max));
153fcf3ce4John Forte	}
154291a2b4Sukumar Swaminathan
155fcf3ce4John Forte	if (hba->intr_flags & EMLXS_MSI_INITED) {
156fcf3ce4John Forte		return (DDI_SUCCESS);
157fcf3ce4John Forte	}
158291a2b4Sukumar Swaminathan
159fcf3ce4John Forte	/* Set max interrupt count if not specified */
160fcf3ce4John Forte	if (max == 0) {
161fcf3ce4John Forte		if ((cfg[CFG_MSI_MODE].current == 2) ||
162fcf3ce4John Forte		    (cfg[CFG_MSI_MODE].current == 3)) {
163fcf3ce4John Forte			max = EMLXS_MSI_MAX_INTRS;
164fcf3ce4John Forte		} else {
165fcf3ce4John Forte			max = 1;
166fcf3ce4John Forte		}
167fcf3ce4John Forte	}
168291a2b4Sukumar Swaminathan
169fcf3ce4John Forte	/* Filter max interrupt count with adapter model specification */
170fcf3ce4John Forte	if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
171fcf3ce4John Forte		max = hba->model_info.intr_limit;
172fcf3ce4John Forte	}
173291a2b4Sukumar Swaminathan
174fcf3ce4John Forte	/* Get the available interrupt types from the kernel */
175fcf3ce4John Forte	types = 0;
176fcf3ce4John Forte	ret = ddi_intr_get_supported_types(hba->dip, &types);
177fcf3ce4John Forte
178fcf3ce4John Forte	if ((ret != DDI_SUCCESS)) {
179fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
180fcf3ce4John Forte		    "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
181fcf3ce4John Forte
182fcf3ce4John Forte		/* Default to fixed type */
183fcf3ce4John Forte		types = DDI_INTR_TYPE_FIXED;
184fcf3ce4John Forte	}
185291a2b4Sukumar Swaminathan
186fcf3ce4John Forte	/* Check if fixed interrupts are being forced */
187fcf3ce4John Forte	if (cfg[CFG_MSI_MODE].current == 0) {
188fcf3ce4John Forte		types &= DDI_INTR_TYPE_FIXED;
189fcf3ce4John Forte	}
190291a2b4Sukumar Swaminathan
191fcf3ce4John Forte	/* Check if MSI interrupts are being forced */
192fcf3ce4John Forte	else if ((cfg[CFG_MSI_MODE].current == 1) ||
193fcf3ce4John Forte	    (cfg[CFG_MSI_MODE].current == 2)) {
194fcf3ce4John Forte		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
195fcf3ce4John Forte	}
196291a2b4Sukumar Swaminathan
197fcf3ce4John Fortebegin:
198fcf3ce4John Forte
199fcf3ce4John Forte	/* Set interrupt type and interrupt count */
200fcf3ce4John Forte	type = 0;
201fcf3ce4John Forte
202fcf3ce4John Forte	/* Check if MSIX is fully supported */
203fcf3ce4John Forte	if ((types & DDI_INTR_TYPE_MSIX) &&
204fcf3ce4John Forte	    (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
205fcf3ce4John Forte		/* Get the max interrupt count from the adapter */
206fcf3ce4John Forte		nintrs = 0;
207fcf3ce4John Forte		ret =
208291a2b4Sukumar Swaminathan		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX,
209291a2b4Sukumar Swaminathan		    &nintrs);
210fcf3ce4John Forte
211fcf3ce4John Forte		if (ret == DDI_SUCCESS && nintrs) {
212fcf3ce4John Forte			type = DDI_INTR_TYPE_MSIX;
2138f23e9fHans Rosenfeld			(void) strlcpy(s_type, "TYPE_MSIX", sizeof (s_type));
214fcf3ce4John Forte			goto initialize;
215fcf3ce4John Forte		}
216fcf3ce4John Forte	}
217291a2b4Sukumar Swaminathan
218fcf3ce4John Forte	/* Check if MSI is fully supported */
219fcf3ce4John Forte	if ((types & DDI_INTR_TYPE_MSI) &&
220fcf3ce4John Forte	    (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
221fcf3ce4John Forte		/* Get the max interrupt count from the adapter */
222fcf3ce4John Forte		nintrs = 0;
223291a2b4Sukumar Swaminathan		ret =
224291a2b4Sukumar Swaminathan		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
225fcf3ce4John Forte
226fcf3ce4John Forte		if (ret == DDI_SUCCESS && nintrs) {
227fcf3ce4John Forte			type = DDI_INTR_TYPE_MSI;
2288f23e9fHans Rosenfeld			(void) strlcpy(s_type, "TYPE_MSI", sizeof (s_type));
229fcf3ce4John Forte			goto initialize;
230fcf3ce4John Forte		}
231fcf3ce4John Forte	}
232291a2b4Sukumar Swaminathan
233fcf3ce4John Forte	/* Check if fixed interrupts are fully supported */
234fcf3ce4John Forte	if ((types & DDI_INTR_TYPE_FIXED) &&
235fcf3ce4John Forte	    (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
236fcf3ce4John Forte		/* Get the max interrupt count from the adapter */
237fcf3ce4John Forte		nintrs = 0;
238fcf3ce4John Forte		ret =
239291a2b4Sukumar Swaminathan		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED,
240291a2b4Sukumar Swaminathan		    &nintrs);
241fcf3ce4John Forte
242fcf3ce4John Forte		if (ret == DDI_SUCCESS) {
243fcf3ce4John Forte			type = DDI_INTR_TYPE_FIXED;
2448f23e9fHans Rosenfeld			(void) strlcpy(s_type, "TYPE_FIXED", sizeof (s_type));
245fcf3ce4John Forte			goto initialize;
246fcf3ce4John Forte		}
247fcf3ce4John Forte	}
248291a2b4Sukumar Swaminathan
249fcf3ce4John Forte	goto init_failed;
250fcf3ce4John Forte
251fcf3ce4John Forte
252fcf3ce4John Forteinitialize:
253fcf3ce4John Forte
254fcf3ce4John Forte	pass++;
255fcf3ce4John Forte	mode = 0;
256fcf3ce4John Forte	actual = 0;
257fcf3ce4John Forte	htable = NULL;
258fcf3ce4John Forte	intr_pri = NULL;
259fcf3ce4John Forte	intr_cap = NULL;
260fcf3ce4John Forte	hilevel_pri = 0;
261fcf3ce4John Forte
262fcf3ce4John Forte	if (pass == 1) {
263fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
264291a2b4Sukumar Swaminathan		    "MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
265291a2b4Sukumar Swaminathan		    cfg[CFG_MSI_MODE].current, types, nintrs);
266fcf3ce4John Forte	}
267291a2b4Sukumar Swaminathan
268fcf3ce4John Forte	/* Validate interrupt count */
269fcf3ce4John Forte	count = min(nintrs, max);
270fcf3ce4John Forte
271fcf3ce4John Forte	if (count >= 8) {
272fcf3ce4John Forte		count = 8;
273fcf3ce4John Forte	} else if (count >= 4) {
274fcf3ce4John Forte		count = 4;
275fcf3ce4John Forte	} else if (count >= 2) {
276fcf3ce4John Forte		count = 2;
277fcf3ce4John Forte	} else {
278fcf3ce4John Forte		count = 1;
279fcf3ce4John Forte	}
280fcf3ce4John Forte
281fcf3ce4John Forte	/* Allocate an array of interrupt handles */
282fcf3ce4John Forte	htable =
283291a2b4Sukumar Swaminathan	    kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)),
284291a2b4Sukumar Swaminathan	    KM_SLEEP);
285fcf3ce4John Forte
286fcf3ce4John Forte	/* Allocate 'count' interrupts */
287291a2b4Sukumar Swaminathan	ret =
288291a2b4Sukumar Swaminathan	    ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
289fcf3ce4John Forte	    &actual, DDI_INTR_ALLOC_NORMAL);
290fcf3ce4John Forte
291fcf3ce4John Forte	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2928252773Sukumar Swaminathan	    "MSI: %s: count=%d actual=%d ret=%d", s_type, count, actual, ret);
293fcf3ce4John Forte
294fcf3ce4John Forte	if ((ret != DDI_SUCCESS) || (actual == 0)) {
295fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
296fcf3ce4John Forte		    "MSI: Unable to allocate interrupts. error=%d", ret);
297fcf3ce4John Forte
298a9800beGarrett D'Amore		actual = 0;
299fcf3ce4John Forte		goto init_failed;
300fcf3ce4John Forte	}
301291a2b4Sukumar Swaminathan
302fcf3ce4John Forte	if (actual != count) {
303fcf3ce4John Forte		/* Validate actual count */
304fcf3ce4John Forte		if (actual >= 8) {
305fcf3ce4John Forte			new_actual = 8;
306fcf3ce4John Forte		} else if (actual >= 4) {
307fcf3ce4John Forte			new_actual = 4;
308fcf3ce4John Forte		} else if (actual >= 2) {
309fcf3ce4John Forte			new_actual = 2;
310fcf3ce4John Forte		} else {
311fcf3ce4John Forte			new_actual = 1;
312fcf3ce4John Forte		}
313fcf3ce4John Forte
314fcf3ce4John Forte		if (new_actual < actual) {
315fcf3ce4John Forte			/* Free extra handles */
316fcf3ce4John Forte			for (i = new_actual; i < actual; i++) {
317fcf3ce4John Forte				(void) ddi_intr_free(htable[i]);
318fcf3ce4John Forte			}
319fcf3ce4John Forte
320fcf3ce4John Forte			actual = new_actual;
321fcf3ce4John Forte		}
322291a2b4Sukumar Swaminathan
323fcf3ce4John Forte		/* Allocate a new array of interrupt handles */
324fcf3ce4John Forte		new_htable =
325fcf3ce4John Forte		    kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
326fcf3ce4John Forte		    KM_SLEEP);
327fcf3ce4John Forte
328fcf3ce4John Forte		/* Copy old array to new array */
329fcf3ce4John Forte		bcopy((uint8_t *)htable, (uint8_t *)new_htable,
330fcf3ce4John Forte		    (actual * sizeof (ddi_intr_handle_t)));
331fcf3ce4John Forte
332fcf3ce4John Forte		/* Free the old array */
333fcf3ce4John Forte		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
334fcf3ce4John Forte
335fcf3ce4John Forte		htable = new_htable;
336fcf3ce4John Forte		count = actual;
337fcf3ce4John Forte	}
338291a2b4Sukumar Swaminathan
339fcf3ce4John Forte	/* Allocate interrupt priority table */
340fcf3ce4John Forte	intr_pri =
341fcf3ce4John Forte	    (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
342fcf3ce4John Forte	    KM_SLEEP);
343fcf3ce4John Forte
344fcf3ce4John Forte	/* Allocate interrupt capability table */
345fcf3ce4John Forte	intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
346fcf3ce4John Forte
347fcf3ce4John Forte	/* Get minimum hilevel priority */
348fcf3ce4John Forte	hilevel_pri = ddi_intr_get_hilevel_pri();
349fcf3ce4John Forte
350fcf3ce4John Forte	/* Fill the priority and capability tables */
351fcf3ce4John Forte	for (i = 0; i < count; ++i) {
352fcf3ce4John Forte		ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
353fcf3ce4John Forte
354fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
355fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
356fcf3ce4John Forte			    "MSI: ddi_intr_get_pri(%d) failed. "
357291a2b4Sukumar Swaminathan			    "handle=%p ret=%d",
358291a2b4Sukumar Swaminathan			    i, &htable[i], ret);
359fcf3ce4John Forte
360fcf3ce4John Forte			/* Clean up the interrupts */
361fcf3ce4John Forte			goto init_failed;
362fcf3ce4John Forte		}
363291a2b4Sukumar Swaminathan
364fcf3ce4John Forte		if (intr_pri[i] >= hilevel_pri) {
365fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
366fcf3ce4John Forte			    "MSI: Interrupt(%d) level too high. "
367fcf3ce4John Forte			    "pri=0x%x hilevel=0x%x",
368fcf3ce4John Forte			    i, intr_pri[i], hilevel_pri);
369fcf3ce4John Forte
370fcf3ce4John Forte			/* Clean up the interrupts */
371fcf3ce4John Forte			goto init_failed;
372fcf3ce4John Forte		}
373291a2b4Sukumar Swaminathan
374fcf3ce4John Forte		ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
375fcf3ce4John Forte
376fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
377fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
378291a2b4Sukumar Swaminathan			    "MSI: ddi_intr_get_cap(%d) failed. "
379291a2b4Sukumar Swaminathan			    "handle=%p ret=%d",
380291a2b4Sukumar Swaminathan			    i, &htable[i], ret);
381fcf3ce4John Forte
382fcf3ce4John Forte			/* Clean up the interrupts */
383fcf3ce4John Forte			goto init_failed;
384fcf3ce4John Forte		}
385291a2b4Sukumar Swaminathan
386fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
387291a2b4Sukumar Swaminathan		    "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
388291a2b4Sukumar Swaminathan		    intr_cap[i], intr_pri[i], hilevel_pri);
389fcf3ce4John Forte
390fcf3ce4John Forte	}
391fcf3ce4John Forte
392fcf3ce4John Forte	/* Set mode */
393fcf3ce4John Forte	switch (count) {
394fcf3ce4John Forte	case 8:
395fcf3ce4John Forte		mode = EMLXS_MSI_MODE8;
396fcf3ce4John Forte		break;
397fcf3ce4John Forte
398fcf3ce4John Forte	case 4:
399fcf3ce4John Forte		mode = EMLXS_MSI_MODE4;
400fcf3ce4John Forte		break;
401fcf3ce4John Forte
402fcf3ce4John Forte	case 2:
403fcf3ce4John Forte		mode = EMLXS_MSI_MODE2;
404fcf3ce4John Forte		break;
405fcf3ce4John Forte
406fcf3ce4John Forte	default:
407fcf3ce4John Forte		mode = EMLXS_MSI_MODE1;
408fcf3ce4John Forte	}
409fcf3ce4John Forte
410fcf3ce4John Forte	/* Save the info */
411fcf3ce4John Forte	hba->intr_htable = htable;
412fcf3ce4John Forte	hba->intr_count = count;
413fcf3ce4John Forte	hba->intr_pri = intr_pri;
414fcf3ce4John Forte	hba->intr_cap = intr_cap;
415fcf3ce4John Forte	hba->intr_type = type;
416291a2b4Sukumar Swaminathan	hba->intr_arg = (void *)((unsigned long)intr_pri[0]);
417fcf3ce4John Forte	hba->intr_mask = emlxs_msi_mask[mode];
418fcf3ce4John Forte
419fcf3ce4John Forte	hba->intr_cond = 0;
4208252773Sukumar Swaminathan
4218252773Sukumar Swaminathan	/* Adjust number of channels based on intr_count */
4228252773Sukumar Swaminathan	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4238252773Sukumar Swaminathan		hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
4248252773Sukumar Swaminathan	}
4258252773Sukumar Swaminathan
426fcf3ce4John Forte	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
427fcf3ce4John Forte		hba->intr_map[i] = emlxs_msi_map[mode][i];
428fcf3ce4John Forte		hba->intr_cond |= emlxs_msi_map[mode][i];
429fcf3ce4John Forte
4308f23e9fHans Rosenfeld		mutex_init(&hba->intr_lock[i], NULL, MUTEX_DRIVER,
431a9800beGarrett D'Amore		    DDI_INTR_PRI(hba->intr_arg));
432fcf3ce4John Forte	}
433fcf3ce4John Forte
434fcf3ce4John Forte	/* Set flag to indicate support */
435fcf3ce4John Forte	hba->intr_flags |= EMLXS_MSI_INITED;
436fcf3ce4John Forte
437fcf3ce4John Forte	/* Create the interrupt threads */
4388252773Sukumar Swaminathan	for (i = 0; i < hba->chan_count; i++) {
4398f23e9fHans Rosenfeld		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
440a9800beGarrett D'Amore		    DDI_INTR_PRI(hba->intr_arg));
441fcf3ce4John Forte
4428252773Sukumar Swaminathan		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
443fcf3ce4John Forte	}
444fcf3ce4John Forte
445fcf3ce4John Forte	return (DDI_SUCCESS);
446fcf3ce4John Forte
447fcf3ce4John Forteinit_failed:
448fcf3ce4John Forte
449fcf3ce4John Forte	if (intr_cap) {
450fcf3ce4John Forte		kmem_free(intr_cap, (count * sizeof (int32_t)));
451fcf3ce4John Forte	}
452291a2b4Sukumar Swaminathan
453fcf3ce4John Forte	if (intr_pri) {
454fcf3ce4John Forte		kmem_free(intr_pri, (count * sizeof (int32_t)));
455fcf3ce4John Forte	}
456291a2b4Sukumar Swaminathan
457fcf3ce4John Forte	if (htable) {
458fcf3ce4John Forte		/* Process the interrupt handlers */
459fcf3ce4John Forte		for (i = 0; i < actual; i++) {
460fcf3ce4John Forte			/* Free the handle[i] */
461fcf3ce4John Forte			(void) ddi_intr_free(htable[i]);
462fcf3ce4John Forte		}
463fcf3ce4John Forte
464fcf3ce4John Forte		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
465fcf3ce4John Forte	}
466291a2b4Sukumar Swaminathan
467fcf3ce4John Forte	/* Initialize */
468fcf3ce4John Forte	hba->intr_htable = NULL;
469fcf3ce4John Forte	hba->intr_count = 0;
470fcf3ce4John Forte	hba->intr_pri = NULL;
471fcf3ce4John Forte	hba->intr_cap = NULL;
472fcf3ce4John Forte	hba->intr_type = 0;
473fcf3ce4John Forte	hba->intr_arg = NULL;
474fcf3ce4John Forte	hba->intr_cond = 0;
475fcf3ce4John Forte	bzero(hba->intr_map, sizeof (hba->intr_map));
476fcf3ce4John Forte	bzero(hba->intr_lock, sizeof (hba->intr_lock));
477fcf3ce4John Forte
478fcf3ce4John Forte	if (type == DDI_INTR_TYPE_MSIX) {
479fcf3ce4John Forte		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
480fcf3ce4John Forte		goto begin;
481fcf3ce4John Forte	} else if (type == DDI_INTR_TYPE_MSI) {
482fcf3ce4John Forte		types &= DDI_INTR_TYPE_FIXED;
483fcf3ce4John Forte		goto begin;
484fcf3ce4John Forte	}
485291a2b4Sukumar Swaminathan
486fcf3ce4John Forte	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
487fcf3ce4John Forte	    "MSI: Unable to initialize interrupts");
488fcf3ce4John Forte
489fcf3ce4John Forte	return (DDI_FAILURE);
490fcf3ce4John Forte
491fcf3ce4John Forte
4928252773Sukumar Swaminathan} /* emlxs_msi_init() */
493fcf3ce4John Forte
494fcf3ce4John Forte
495fcf3ce4John Forte/* EMLXS_INTR_UNINIT */
496fcf3ce4John Forteint32_t
497fcf3ce4John Forteemlxs_msi_uninit(emlxs_hba_t *hba)
498fcf3ce4John Forte{
499fcf3ce4John Forte	uint32_t count;
500fcf3ce4John Forte	int32_t i;
501fcf3ce4John Forte	ddi_intr_handle_t *htable;
502fcf3ce4John Forte	uint32_t *intr_pri;
503fcf3ce4John Forte	int32_t *intr_cap;
504fcf3ce4John Forte	int32_t ret;
505fcf3ce4John Forte
506fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
507fcf3ce4John Forte		return (emlxs_intx_uninit(hba));
508fcf3ce4John Forte	}
509291a2b4Sukumar Swaminathan
510fcf3ce4John Forte	/*
511291a2b4Sukumar Swaminathan	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5128f23e9fHans Rosenfeld	 *    "MSI: msi_uninit called. flags=%x",
513291a2b4Sukumar Swaminathan	 *    hba->intr_flags);
514fcf3ce4John Forte	 */
515fcf3ce4John Forte
516fcf3ce4John Forte	/* Make sure interrupts have been removed first */
517fcf3ce4John Forte	if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
518fcf3ce4John Forte		ret = emlxs_msi_remove(hba);
519fcf3ce4John Forte
520fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
521fcf3ce4John Forte			return (ret);
522fcf3ce4John Forte		}
523fcf3ce4John Forte	}
524291a2b4Sukumar Swaminathan
525fcf3ce4John Forte	/* Check if the interrupts are still initialized */
526fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
527fcf3ce4John Forte		return (DDI_SUCCESS);
528fcf3ce4John Forte	}
529fcf3ce4John Forte	hba->intr_flags &= ~EMLXS_MSI_INITED;
530fcf3ce4John Forte
531fcf3ce4John Forte	/* Get handle table parameters */
532fcf3ce4John Forte	htable = hba->intr_htable;
533fcf3ce4John Forte	count = hba->intr_count;
534fcf3ce4John Forte	intr_pri = hba->intr_pri;
535fcf3ce4John Forte	intr_cap = hba->intr_cap;
536fcf3ce4John Forte
537fcf3ce4John Forte	/* Clean up */
538fcf3ce4John Forte	hba->intr_count = 0;
539fcf3ce4John Forte	hba->intr_htable = NULL;
540fcf3ce4John Forte	hba->intr_pri = NULL;
541fcf3ce4John Forte	hba->intr_cap = NULL;
542fcf3ce4John Forte	hba->intr_type = 0;
543fcf3ce4John Forte	hba->intr_arg = NULL;
544fcf3ce4John Forte	hba->intr_cond = 0;
545fcf3ce4John Forte	bzero(hba->intr_map, sizeof (hba->intr_map));
546fcf3ce4John Forte
547fcf3ce4John Forte	if (intr_cap) {
548fcf3ce4John Forte		kmem_free(intr_cap, (count * sizeof (int32_t)));
549fcf3ce4John Forte	}
550291a2b4Sukumar Swaminathan
551fcf3ce4John Forte	if (intr_pri) {
552fcf3ce4John Forte		kmem_free(intr_pri, (count * sizeof (int32_t)));
553fcf3ce4John Forte	}
554291a2b4Sukumar Swaminathan
555fcf3ce4John Forte	if (htable) {
556fcf3ce4John Forte		/* Process the interrupt handlers */
557fcf3ce4John Forte		for (i = 0; i < count; ++i) {
558fcf3ce4John Forte			/* Free the handle[i] */
559291a2b4Sukumar Swaminathan			ret = ddi_intr_free(htable[i]);
560fcf3ce4John Forte		}
561fcf3ce4John Forte
562fcf3ce4John Forte		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
563fcf3ce4John Forte	}
564291a2b4Sukumar Swaminathan
565fcf3ce4John Forte	/* Destroy the intr locks */
566fcf3ce4John Forte	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
567fcf3ce4John Forte		mutex_destroy(&hba->intr_lock[i]);
568fcf3ce4John Forte	}
569fcf3ce4John Forte
570fcf3ce4John Forte	/* Destroy the interrupt threads */
5718252773Sukumar Swaminathan	for (i = 0; i < hba->chan_count; i++) {
5728252773Sukumar Swaminathan		emlxs_thread_destroy(&hba->chan[i].intr_thread);
5738252773Sukumar Swaminathan		mutex_destroy(&hba->chan[i].rsp_lock);
574fcf3ce4John Forte	}
575fcf3ce4John Forte
576fcf3ce4John Forte	/*
577291a2b4Sukumar Swaminathan	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5788f23e9fHans Rosenfeld	 *    "MSI: msi_uninit done. flags=%x",
579291a2b4Sukumar Swaminathan	 *    hba->intr_flags);
580fcf3ce4John Forte	 */
581fcf3ce4John Forte
582fcf3ce4John Forte	return (DDI_SUCCESS);
583fcf3ce4John Forte
5848252773Sukumar Swaminathan} /* emlxs_msi_uninit() */
585fcf3ce4John Forte
586fcf3ce4John Forte
587fcf3ce4John Forte/* EMLXS_INTR_ADD */
588fcf3ce4John Forteint32_t
589fcf3ce4John Forteemlxs_msi_add(emlxs_hba_t *hba)
590fcf3ce4John Forte{
591fcf3ce4John Forte	emlxs_port_t *port = &PPORT;
592fcf3ce4John Forte	int32_t count;
593fcf3ce4John Forte	int32_t i;
594fcf3ce4John Forte	int32_t ret;
595fcf3ce4John Forte	ddi_intr_handle_t *htable = NULL;
596fcf3ce4John Forte	int32_t *intr_cap = NULL;
597fcf3ce4John Forte
598fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
599fcf3ce4John Forte		return (emlxs_intx_add(hba));
600fcf3ce4John Forte	}
601291a2b4Sukumar Swaminathan
602fcf3ce4John Forte	/* Check if interrupts have already been added */
603fcf3ce4John Forte	if (hba->intr_flags & EMLXS_MSI_ADDED) {
604fcf3ce4John Forte		return (DDI_SUCCESS);
605fcf3ce4John Forte	}
606291a2b4Sukumar Swaminathan
607fcf3ce4John Forte	/* Check if interrupts have been initialized */
608fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
609fcf3ce4John Forte		ret = emlxs_msi_init(hba, 0);
610fcf3ce4John Forte
611fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
612fcf3ce4John Forte			return (ret);
613fcf3ce4John Forte		}
614fcf3ce4John Forte	}
615291a2b4Sukumar Swaminathan
616fcf3ce4John Forte	/* Get handle table parameters */
617fcf3ce4John Forte	htable = hba->intr_htable;
618fcf3ce4John Forte	count = hba->intr_count;
619fcf3ce4John Forte	intr_cap = hba->intr_cap;
620fcf3ce4John Forte
621fcf3ce4John Forte	/* Add the interrupt handlers */
622fcf3ce4John Forte	for (i = 0; i < count; ++i) {
623fcf3ce4John Forte		/* add handler for handle[i] */
624291a2b4Sukumar Swaminathan		ret =
6258252773Sukumar Swaminathan		    ddi_intr_add_handler(htable[i], EMLXS_SLI_MSI_INTR,
626291a2b4Sukumar Swaminathan		    (char *)hba, (char *)((unsigned long)i));
627fcf3ce4John Forte
628fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
629fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
630291a2b4Sukumar Swaminathan			    "MSI: ddi_intr_add_handler(%d) failed. "
631291a2b4Sukumar Swaminathan			    "handle=%p ret=%d",
632291a2b4Sukumar Swaminathan			    i, &htable[i], ret);
633fcf3ce4John Forte
634fcf3ce4John Forte			/* Process the remaining interrupt handlers */
635fcf3ce4John Forte			while (i) {
636fcf3ce4John Forte				/* Decrement i */
637fcf3ce4John Forte				i--;
638fcf3ce4John Forte
639fcf3ce4John Forte				/* Remove the handler */
640fcf3ce4John Forte				ret = ddi_intr_remove_handler(htable[i]);
641fcf3ce4John Forte
642fcf3ce4John Forte			}
643fcf3ce4John Forte
644fcf3ce4John Forte			return (DDI_FAILURE);
645fcf3ce4John Forte		}
646fcf3ce4John Forte	}
647fcf3ce4John Forte
648fcf3ce4John Forte	/* Enable the interrupts */
649fcf3ce4John Forte	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
650fcf3ce4John Forte		ret = ddi_intr_block_enable(htable, count);
651fcf3ce4John Forte
652fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
653fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
654fcf3ce4John Forte			    "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
655fcf3ce4John Forte			    count, ret);
656fcf3ce4John Forte
657fcf3ce4John Forte			for (i = 0; i < count; ++i) {
658fcf3ce4John Forte				ret = ddi_intr_enable(htable[i]);
659fcf3ce4John Forte
660fcf3ce4John Forte				if (ret != DDI_SUCCESS) {
661fcf3ce4John Forte					EMLXS_MSGF(EMLXS_CONTEXT,
662fcf3ce4John Forte					    &emlxs_init_debug_msg,
663fcf3ce4John Forte					    "MSI: ddi_intr_enable(%d) failed. "
664291a2b4Sukumar Swaminathan					    "ret=%d",
665291a2b4Sukumar Swaminathan					    i, ret);
666fcf3ce4John Forte				}
667fcf3ce4John Forte			}
668fcf3ce4John Forte		}
669fcf3ce4John Forte	} else {
670fcf3ce4John Forte		for (i = 0; i < count; ++i) {
671fcf3ce4John Forte			ret = ddi_intr_enable(htable[i]);
672fcf3ce4John Forte
673fcf3ce4John Forte			if (ret != DDI_SUCCESS) {
674291a2b4Sukumar Swaminathan				EMLXS_MSGF(EMLXS_CONTEXT,
675291a2b4Sukumar Swaminathan				    &emlxs_init_debug_msg,
676fcf3ce4John Forte				    "MSI: ddi_intr_enable(%d) failed. ret=%d",
677fcf3ce4John Forte				    i, ret);
678fcf3ce4John Forte			}
679fcf3ce4John Forte		}
680fcf3ce4John Forte	}
681fcf3ce4John Forte
682fcf3ce4John Forte
683fcf3ce4John Forte	/* Set flag to indicate support */
684fcf3ce4John Forte	hba->intr_flags |= EMLXS_MSI_ADDED;
685fcf3ce4John Forte
686fcf3ce4John Forte	return (DDI_SUCCESS);
687fcf3ce4John Forte
6888252773Sukumar Swaminathan} /* emlxs_msi_add() */
689fcf3ce4John Forte
690fcf3ce4John Forte
691fcf3ce4John Forte
692fcf3ce4John Forte/* EMLXS_INTR_REMOVE */
693fcf3ce4John Forteint32_t
694fcf3ce4John Forteemlxs_msi_remove(emlxs_hba_t *hba)
695fcf3ce4John Forte{
696fcf3ce4John Forte	emlxs_port_t *port = &PPORT;
697fcf3ce4John Forte	uint32_t count;
698fcf3ce4John Forte	int32_t i;
699fcf3ce4John Forte	ddi_intr_handle_t *htable;
700fcf3ce4John Forte	int32_t *intr_cap;
701fcf3ce4John Forte	int32_t ret;
702fcf3ce4John Forte
703fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
704fcf3ce4John Forte		return (emlxs_intx_remove(hba));
705fcf3ce4John Forte	}
706291a2b4Sukumar Swaminathan
707fcf3ce4John Forte	/*
708291a2b4Sukumar Swaminathan	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
7098f23e9fHans Rosenfeld	 *    "MSI: msi_remove called. flags=%x",
710291a2b4Sukumar Swaminathan	 *    hba->intr_flags);
711fcf3ce4John Forte	 */
712fcf3ce4John Forte
713fcf3ce4John Forte	/* Check if interrupts have already been removed */
714fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
715fcf3ce4John Forte		return (DDI_SUCCESS);
716fcf3ce4John Forte	}
717fcf3ce4John Forte	hba->intr_flags &= ~EMLXS_MSI_ADDED;
718fcf3ce4John Forte
719fcf3ce4John Forte	/* Disable all adapter interrupts */
7208252773Sukumar Swaminathan	EMLXS_SLI_DISABLE_INTR(hba, 0);
721fcf3ce4John Forte
722fcf3ce4John Forte	/* Get handle table parameters */
723fcf3ce4John Forte	htable = hba->intr_htable;
724fcf3ce4John Forte	count = hba->intr_count;
725fcf3ce4John Forte	intr_cap = hba->intr_cap;
726fcf3ce4John Forte
727fcf3ce4John Forte	/* Disable the interrupts */
728fcf3ce4John Forte	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
729fcf3ce4John Forte		ret = ddi_intr_block_disable(htable, count);
730fcf3ce4John Forte
731fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
732fcf3ce4John Forte			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
733fcf3ce4John Forte			    "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
734fcf3ce4John Forte			    count, ret);
735fcf3ce4John Forte
736fcf3ce4John Forte			for (i = 0; i < count; i++) {
737fcf3ce4John Forte				ret = ddi_intr_disable(htable[i]);
738fcf3ce4John Forte
739fcf3ce4John Forte				if (ret != DDI_SUCCESS) {
740fcf3ce4John Forte					EMLXS_MSGF(EMLXS_CONTEXT,
741fcf3ce4John Forte					    &emlxs_init_debug_msg,
742fcf3ce4John Forte					    "MSI: ddi_intr_disable(%d) failed. "
743291a2b4Sukumar Swaminathan					    "ret=%d",
744291a2b4Sukumar Swaminathan					    i, ret);
745fcf3ce4John Forte				}
746fcf3ce4John Forte			}
747fcf3ce4John Forte		}
748fcf3ce4John Forte	} else {
749fcf3ce4John Forte		for (i = 0; i < count; i++) {
750fcf3ce4John Forte			ret = ddi_intr_disable(htable[i]);
751fcf3ce4John Forte
752fcf3ce4John Forte			if (ret != DDI_SUCCESS) {
753291a2b4Sukumar Swaminathan				EMLXS_MSGF(EMLXS_CONTEXT,
754291a2b4Sukumar Swaminathan				    &emlxs_init_debug_msg,
755fcf3ce4John Forte				    "MSI: ddi_intr_disable(%d) failed. ret=%d",
756fcf3ce4John Forte				    i, ret);
757fcf3ce4John Forte			}
758fcf3ce4John Forte		}
759fcf3ce4John Forte	}
760fcf3ce4John Forte
761fcf3ce4John Forte	/* Process the interrupt handlers */
762fcf3ce4John Forte	for (i = 0; i < count; i++) {
763fcf3ce4John Forte		/* Remove the handler */
764fcf3ce4John Forte		ret = ddi_intr_remove_handler(htable[i]);
765fcf3ce4John Forte
766fcf3ce4John Forte
767fcf3ce4John Forte	}
768fcf3ce4John Forte
769fcf3ce4John Forte	return (DDI_SUCCESS);
770fcf3ce4John Forte
7718252773Sukumar Swaminathan} /* emlxs_msi_remove() */
772fcf3ce4John Forte
773291a2b4Sukumar Swaminathan#endif /* MSI_SUPPORT */
774fcf3ce4John Forte
775fcf3ce4John Forte
776fcf3ce4John Forte/* EMLXS_INTR_INIT */
777fcf3ce4John Forte/* ARGSUSED */
778fcf3ce4John Forteint32_t
779fcf3ce4John Forteemlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
780fcf3ce4John Forte{
781fcf3ce4John Forte	emlxs_port_t *port = &PPORT;
7828252773Sukumar Swaminathan	emlxs_config_t *cfg = &CFG;
783fcf3ce4John Forte	int32_t ret;
784fcf3ce4John Forte	uint32_t i;
785fcf3ce4John Forte
786fcf3ce4John Forte	/* Check if interrupts have already been initialized */
787fcf3ce4John Forte	if (hba->intr_flags & EMLXS_INTX_INITED) {
788fcf3ce4John Forte		return (DDI_SUCCESS);
789fcf3ce4John Forte	}
790291a2b4Sukumar Swaminathan
791fcf3ce4John Forte	/* Check if adapter is flagged for INTX support */
792fcf3ce4John Forte	if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
793fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
794fcf3ce4John Forte		    "INTX: %s does not support INTX.  flags=0x%x",
795fcf3ce4John Forte		    hba->model_info.model, hba->model_info.flags);
796fcf3ce4John Forte
797fcf3ce4John Forte		return (DDI_FAILURE);
798fcf3ce4John Forte	}
799291a2b4Sukumar Swaminathan
800fcf3ce4John Forte	/*
801291a2b4Sukumar Swaminathan	 * Interrupt number '0' is a high-level interrupt. This driver
802291a2b4Sukumar Swaminathan	 * does not support having its interrupts mapped above scheduler
803291a2b4Sukumar Swaminathan	 * priority; i.e., we always expect to be able to call general
804291a2b4Sukumar Swaminathan	 * kernel routines that may invoke the scheduler.
805fcf3ce4John Forte	 */
806fcf3ce4John Forte	if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
807fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
808fcf3ce4John Forte		    "INTX: High-level interrupt not supported.");
809fcf3ce4John Forte
810fcf3ce4John Forte		return (DDI_FAILURE);
811fcf3ce4John Forte	}
812291a2b4Sukumar Swaminathan
813fcf3ce4John Forte	/* Get an iblock cookie */
814291a2b4Sukumar Swaminathan	ret =
815291a2b4Sukumar Swaminathan	    ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
816fcf3ce4John Forte	    (ddi_iblock_cookie_t *)&hba->intr_arg);
817fcf3ce4John Forte	if (ret != DDI_SUCCESS) {
818fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
819fcf3ce4John Forte		    "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
820fcf3ce4John Forte
821fcf3ce4John Forte		return (ret);
822fcf3ce4John Forte	}
823291a2b4Sukumar Swaminathan
824fcf3ce4John Forte	hba->intr_flags |= EMLXS_INTX_INITED;
825fcf3ce4John Forte
8268252773Sukumar Swaminathan	hba->intr_count = 1;
8278252773Sukumar Swaminathan	/* Adjust number of channels based on intr_count */
8288252773Sukumar Swaminathan	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
8298252773Sukumar Swaminathan		hba->chan_count = cfg[CFG_NUM_WQ].current;
8308252773Sukumar Swaminathan	}
8318252773Sukumar Swaminathan
832fcf3ce4John Forte	/* Create the interrupt threads */
8338252773Sukumar Swaminathan	for (i = 0; i < hba->chan_count; i++) {
8348f23e9fHans Rosenfeld		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
835a9800beGarrett D'Amore		    DDI_INTR_PRI(hba->intr_arg));
836fcf3ce4John Forte
8378252773Sukumar Swaminathan		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
838fcf3ce4John Forte	}
839fcf3ce4John Forte
840fcf3ce4John Forte	return (DDI_SUCCESS);
841fcf3ce4John Forte
8428252773Sukumar Swaminathan} /* emlxs_intx_init() */
843fcf3ce4John Forte
844fcf3ce4John Forte
845fcf3ce4John Forte/* EMLXS_INTR_UNINIT */
846fcf3ce4John Forteint32_t
847fcf3ce4John Forteemlxs_intx_uninit(emlxs_hba_t *hba)
848fcf3ce4John Forte{
849fcf3ce4John Forte	int32_t ret;
850fcf3ce4John Forte	uint32_t i;
851fcf3ce4John Forte
852fcf3ce4John Forte	/* Make sure interrupts have been removed */
853fcf3ce4John Forte	if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
854fcf3ce4John Forte		ret = emlxs_intx_remove(hba);
855fcf3ce4John Forte
856fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
857fcf3ce4John Forte			return (ret);
858fcf3ce4John Forte		}
859fcf3ce4John Forte	}
860291a2b4Sukumar Swaminathan
861fcf3ce4John Forte	/* Check if the interrupts are still initialized */
862fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
863fcf3ce4John Forte		return (DDI_SUCCESS);
864fcf3ce4John Forte	}
865fcf3ce4John Forte	hba->intr_flags &= ~EMLXS_INTX_INITED;
866fcf3ce4John Forte
867fcf3ce4John Forte	hba->intr_arg = NULL;
868fcf3ce4John Forte
869fcf3ce4John Forte	/* Create the interrupt threads */
8708252773Sukumar Swaminathan	for (i = 0; i < hba->chan_count; i++) {
8718252773Sukumar Swaminathan		emlxs_thread_destroy(&hba->chan[i].intr_thread);
8728252773Sukumar Swaminathan		mutex_destroy(&hba->chan[i].rsp_lock);
873fcf3ce4John Forte	}
874fcf3ce4John Forte
875fcf3ce4John Forte	return (DDI_SUCCESS);
876fcf3ce4John Forte
8778252773Sukumar Swaminathan} /* emlxs_intx_uninit() */
878fcf3ce4John Forte
879fcf3ce4John Forte
880291a2b4Sukumar Swaminathan/*
881291a2b4Sukumar Swaminathan * This is the legacy method for adding interrupts in Solaris
882291a2b4Sukumar Swaminathan * EMLXS_INTR_ADD
883291a2b4Sukumar Swaminathan */
884fcf3ce4John Forteint32_t
885fcf3ce4John Forteemlxs_intx_add(emlxs_hba_t *hba)
886fcf3ce4John Forte{
887fcf3ce4John Forte	emlxs_port_t *port = &PPORT;
888fcf3ce4John Forte	int32_t ret;
889fcf3ce4John Forte
890fcf3ce4John Forte	/* Check if interrupts have already been added */
891fcf3ce4John Forte	if (hba->intr_flags & EMLXS_INTX_ADDED) {
892fcf3ce4John Forte		return (DDI_SUCCESS);
893fcf3ce4John Forte	}
894291a2b4Sukumar Swaminathan
895fcf3ce4John Forte	/* Check if interrupts have been initialized */
896fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
897fcf3ce4John Forte		ret = emlxs_intx_init(hba, 0);
898fcf3ce4John Forte
899fcf3ce4John Forte		if (ret != DDI_SUCCESS) {
900fcf3ce4John Forte			return (ret);
901fcf3ce4John Forte		}
902fcf3ce4John Forte	}
903291a2b4Sukumar Swaminathan
904fcf3ce4John Forte	/* add intrrupt handler routine */
905291a2b4Sukumar Swaminathan	ret = ddi_add_intr((void *)hba->dip,
906291a2b4Sukumar Swaminathan	    (uint_t)EMLXS_INUMBER,
907291a2b4Sukumar Swaminathan	    (ddi_iblock_cookie_t *)&hba->intr_arg,
908291a2b4Sukumar Swaminathan	    (ddi_idevice_cookie_t *)0,
9098252773Sukumar Swaminathan	    (uint_t(*)())EMLXS_SLI_INTX_INTR, (caddr_t)hba);
910fcf3ce4John Forte
911fcf3ce4John Forte	if (ret != DDI_SUCCESS) {
912fcf3ce4John Forte		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
913fcf3ce4John Forte		    "INTX: ddi_add_intr failed. ret=%d", ret);
914fcf3ce4John Forte
915fcf3ce4John Forte		return (ret);
916fcf3ce4John Forte	}
917291a2b4Sukumar Swaminathan
918fcf3ce4John Forte	hba->intr_flags |= EMLXS_INTX_ADDED;
919fcf3ce4John Forte
920fcf3ce4John Forte	return (DDI_SUCCESS);
921fcf3ce4John Forte
9228252773Sukumar Swaminathan} /* emlxs_intx_add() */
923fcf3ce4John Forte
924fcf3ce4John Forte
925fcf3ce4John Forte/* EMLXS_INTR_REMOVE */
926fcf3ce4John Forteint32_t
927fcf3ce4John Forteemlxs_intx_remove(emlxs_hba_t *hba)
928fcf3ce4John Forte{
929fcf3ce4John Forte	/* Check if interrupts have already been removed */
930fcf3ce4John Forte	if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
931fcf3ce4John Forte		return (DDI_SUCCESS);
932fcf3ce4John Forte	}
933fcf3ce4John Forte	hba->intr_flags &= ~EMLXS_INTX_ADDED;
934fcf3ce4John Forte
935fcf3ce4John Forte	/* Diable all adapter interrupts */
9368252773Sukumar Swaminathan	EMLXS_SLI_DISABLE_INTR(hba, 0);
937fcf3ce4John Forte
938fcf3ce4John Forte	/* Remove the interrupt */
939fcf3ce4John Forte	(void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
940fcf3ce4John Forte	    hba->intr_arg);
941fcf3ce4John Forte
942fcf3ce4John Forte	return (DDI_SUCCESS);
943fcf3ce4John Forte
9448252773Sukumar Swaminathan} /* emlxs_intx_remove() */
945fcf3ce4John Forte
946fcf3ce4John Forte
9478252773Sukumar Swaminathanextern void
948fcf3ce4John Forteemlxs_process_link_speed(emlxs_hba_t *hba)
949fcf3ce4John Forte{
950fcf3ce4John Forte	emlxs_vpd_t *vpd;
951fcf3ce4John Forte	emlxs_config_t *cfg;
952fcf3ce4John Forte	uint32_t hi;
953fcf3ce4John Forte
954fcf3ce4John Forte	/*
955291a2b4Sukumar Swaminathan	 * This routine modifies the link-speed config parameter entry
956291a2b4Sukumar Swaminathan	 * based on adapter capabilities
957fcf3ce4John Forte	 */
958fcf3ce4John Forte	vpd = &VPD;
959fcf3ce4John Forte	cfg = &hba->config[CFG_LINK_SPEED];
960fcf3ce4John Forte
9618f23e9fHans Rosenfeld	(void) strlcpy(cfg->help, "Select link speed. [0=Auto",
9628f23e9fHans Rosenfeld	    EMLXS_CFG_HELP_SIZE);
963fcf3ce4John Forte	hi = 0;
964fcf3ce4John Forte
965fcf3ce4John Forte	if (vpd->link_speed & LMT_1GB_CAPABLE) {
9668f23e9fHans Rosenfeld		(void) strlcat(cfg->help, ", 1=1Gb", EMLXS_CFG_HELP_SIZE);
967fcf3ce4John Forte		hi = 1;
968fcf3ce4John Forte	}
969291a2b4Sukumar Swaminathan
970fcf3ce4John Forte	if (vpd->link_speed & LMT_2GB_CAPABLE) {
9718f23e9fHans Rosenfeld		(void) strlcat(cfg->help, ", 2=2Gb", EMLXS_CFG_HELP_SIZE);
972fcf3ce4John Forte		hi = 2;
973fcf3ce4John Forte	}
974291a2b4Sukumar Swaminathan
975fcf3ce4John Forte	if (vpd->link_speed & LMT_4GB_CAPABLE) {
9768f23e9fHans Rosenfeld		(void) strlcat(cfg->help, ", 4=4Gb", EMLXS_CFG_HELP_SIZE);
977fcf3ce4John Forte		hi = 4;
978fcf3ce4John Forte	}
979291a2b4Sukumar Swaminathan
980fcf3ce4John Forte	if (vpd->link_speed & LMT_8GB_CAPABLE) {
9818f23e9fHans Rosenfeld		(void) strlcat(cfg->help, ", 8=8Gb", EMLXS_CFG_HELP_SIZE);
982fcf3ce4John Forte		hi = 8;
983fcf3ce4John Forte	}
984291a2b4Sukumar Swaminathan
985fcf3ce4John Forte	if (vpd->link_speed & LMT_10GB_CAPABLE) {
9868f23e9f