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"},
66a9800bebSGarrett D'Amore 	{PCI_CAP_ID_PCI_HOTPLUG, "PCI_CAP_ID_PCI_HOTPLUG"},
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"},
818f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_PWR_BUDGET, "PCIE_EXT_CAP_ID_PWR_BUDGET"},
828f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_RC_LINK_DECL, "PCIE_EXT_CAP_ID_RC_LINK_DECL"},
838f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "PCIE_EXT_CAP_ID_RC_INT_LINKCTRL"},
848f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_RC_EVNT_CEA, "PCIE_EXT_CAP_ID_RC_EVNT_CEA"},
858f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_MFVC, "PCIE_EXT_CAP_ID_MFVC"},
868f23e9faSHans Rosenfeld 	{PCIE_EXT_CAP_ID_VC_WITH_MFVC, "PCIE_EXT_CAP_ID_VC_WITH_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
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
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
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
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
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 
810fcf3ce44SJohn Forte 		return (DDI_FAILURE);
811fcf3ce44SJohn Forte 	}
812291a2b48SSukumar Swaminathan 
813fcf3ce44SJohn Forte 	/* Get an iblock cookie */
814291a2b48SSukumar Swaminathan 	ret =
815291a2b48SSukumar Swaminathan 	    ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
816fcf3ce44SJohn Forte 	    (ddi_iblock_cookie_t *)&hba->intr_arg);
817fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
818fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
819fcf3ce44SJohn Forte 		    "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
820fcf3ce44SJohn Forte 
821fcf3ce44SJohn Forte 		return (ret);
822fcf3ce44SJohn Forte 	}
823291a2b48SSukumar Swaminathan 
824fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_INTX_INITED;
825fcf3ce44SJohn Forte 
82682527734SSukumar Swaminathan 	hba->intr_count = 1;
82782527734SSukumar Swaminathan 	/* Adjust number of channels based on intr_count */
82882527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
82982527734SSukumar Swaminathan 		hba->chan_count = cfg[CFG_NUM_WQ].current;
83082527734SSukumar Swaminathan 	}
83182527734SSukumar Swaminathan 
832fcf3ce44SJohn Forte 	/* Create the interrupt threads */
83382527734SSukumar Swaminathan 	for (i = 0; i < hba->chan_count; i++) {
8348f23e9faSHans Rosenfeld 		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
835a9800bebSGarrett D'Amore 		    DDI_INTR_PRI(hba->intr_arg));
836fcf3ce44SJohn Forte 
83782527734SSukumar Swaminathan 		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
838fcf3ce44SJohn Forte 	}
839fcf3ce44SJohn Forte 
840fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
841fcf3ce44SJohn Forte 
84282527734SSukumar Swaminathan } /* emlxs_intx_init() */
843fcf3ce44SJohn Forte 
844fcf3ce44SJohn Forte 
845fcf3ce44SJohn Forte /* EMLXS_INTR_UNINIT */
846fcf3ce44SJohn Forte int32_t
847fcf3ce44SJohn Forte emlxs_intx_uninit(emlxs_hba_t *hba)
848fcf3ce44SJohn Forte {
849fcf3ce44SJohn Forte 	int32_t ret;
850fcf3ce44SJohn Forte 	uint32_t i;
851fcf3ce44SJohn Forte 
852fcf3ce44SJohn Forte 	/* Make sure interrupts have been removed */
853fcf3ce44SJohn Forte 	if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
854fcf3ce44SJohn Forte 		ret = emlxs_intx_remove(hba);
855fcf3ce44SJohn Forte 
856fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
857fcf3ce44SJohn Forte 			return (ret);
858fcf3ce44SJohn Forte 		}
859fcf3ce44SJohn Forte 	}
860291a2b48SSukumar Swaminathan 
861fcf3ce44SJohn Forte 	/* Check if the interrupts are still initialized */
862fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
863fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
864fcf3ce44SJohn Forte 	}
865fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_INTX_INITED;
866fcf3ce44SJohn Forte 
867fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
868fcf3ce44SJohn Forte 
869fcf3ce44SJohn Forte 	/* Create the interrupt threads */
87082527734SSukumar Swaminathan 	for (i = 0; i < hba->chan_count; i++) {
87182527734SSukumar Swaminathan 		emlxs_thread_destroy(&hba->chan[i].intr_thread);
87282527734SSukumar Swaminathan 		mutex_destroy(&hba->chan[i].rsp_lock);
873fcf3ce44SJohn Forte 	}
874fcf3ce44SJohn Forte 
875fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
876fcf3ce44SJohn Forte 
87782527734SSukumar Swaminathan } /* emlxs_intx_uninit() */
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte 
880291a2b48SSukumar Swaminathan /*
881291a2b48SSukumar Swaminathan  * This is the legacy method for adding interrupts in Solaris
882291a2b48SSukumar Swaminathan  * EMLXS_INTR_ADD
883291a2b48SSukumar Swaminathan  */
884fcf3ce44SJohn Forte int32_t
885fcf3ce44SJohn Forte emlxs_intx_add(emlxs_hba_t *hba)
886fcf3ce44SJohn Forte {
887fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
888fcf3ce44SJohn Forte 	int32_t ret;
889fcf3ce44SJohn Forte 
890fcf3ce44SJohn Forte 	/* Check if interrupts have already been added */
891fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_INTX_ADDED) {
892fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
893fcf3ce44SJohn Forte 	}
894291a2b48SSukumar Swaminathan 
895fcf3ce44SJohn Forte 	/* Check if interrupts have been initialized */
896fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
897fcf3ce44SJohn Forte 		ret = emlxs_intx_init(hba, 0);
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
900fcf3ce44SJohn Forte 			return (ret);
901fcf3ce44SJohn Forte 		}
902fcf3ce44SJohn Forte 	}
903291a2b48SSukumar Swaminathan 
904fcf3ce44SJohn Forte 	/* add intrrupt handler routine */
905291a2b48SSukumar Swaminathan 	ret = ddi_add_intr((void *)hba->dip,
906291a2b48SSukumar Swaminathan 	    (uint_t)EMLXS_INUMBER,
907291a2b48SSukumar Swaminathan 	    (ddi_iblock_cookie_t *)&hba->intr_arg,
908291a2b48SSukumar Swaminathan 	    (ddi_idevice_cookie_t *)0,
90982527734SSukumar Swaminathan 	    (uint_t(*)())EMLXS_SLI_INTX_INTR, (caddr_t)hba);
910fcf3ce44SJohn Forte 
911fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
912fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
913fcf3ce44SJohn Forte 		    "INTX: ddi_add_intr failed. ret=%d", ret);
914fcf3ce44SJohn Forte 
915fcf3ce44SJohn Forte 		return (ret);
916fcf3ce44SJohn Forte 	}
917291a2b48SSukumar Swaminathan 
918fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_INTX_ADDED;
919fcf3ce44SJohn Forte 
920fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
921fcf3ce44SJohn Forte 
92282527734SSukumar Swaminathan } /* emlxs_intx_add() */
923fcf3ce44SJohn Forte 
924fcf3ce44SJohn Forte 
925fcf3ce44SJohn Forte /* EMLXS_INTR_REMOVE */
926fcf3ce44SJohn Forte int32_t
927fcf3ce44SJohn Forte emlxs_intx_remove(emlxs_hba_t *hba)
928fcf3ce44SJohn Forte {
929fcf3ce44SJohn Forte 	/* Check if interrupts have already been removed */
930fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
931fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
932fcf3ce44SJohn Forte 	}
933fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_INTX_ADDED;
934fcf3ce44SJohn Forte 
935fcf3ce44SJohn Forte 	/* Diable all adapter interrupts */
93682527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
937fcf3ce44SJohn Forte 
938fcf3ce44SJohn Forte 	/* Remove the interrupt */
939fcf3ce44SJohn Forte 	(void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
940fcf3ce44SJohn Forte 	    hba->intr_arg);
941fcf3ce44SJohn Forte 
942fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
943fcf3ce44SJohn Forte 
94482527734SSukumar Swaminathan } /* emlxs_intx_remove() */
945fcf3ce44SJohn Forte 
946fcf3ce44SJohn Forte 
94782527734SSukumar Swaminathan extern void
948fcf3ce44SJohn Forte emlxs_process_link_speed(emlxs_hba_t *hba)
949fcf3ce44SJohn Forte {
950fcf3ce44SJohn Forte 	emlxs_vpd_t *vpd;
951fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
952fcf3ce44SJohn Forte 	uint32_t hi;
953fcf3ce44SJohn Forte 
954fcf3ce44SJohn Forte 	/*
955291a2b48SSukumar Swaminathan 	 * This routine modifies the link-speed config parameter entry
956291a2b48SSukumar Swaminathan 	 * based on adapter capabilities
957fcf3ce44SJohn Forte 	 */
958fcf3ce44SJohn Forte 	vpd = &VPD;
959fcf3ce44SJohn Forte 	cfg = &hba->config[CFG_LINK_SPEED];
960fcf3ce44SJohn Forte 
9618f23e9faSHans Rosenfeld 	(void) strlcpy(cfg->help, "Select link speed. [0=Auto",
9628f23e9faSHans Rosenfeld 	    EMLXS_CFG_HELP_SIZE);
963fcf3ce44SJohn Forte 	hi = 0;
964fcf3ce44SJohn Forte 
965fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
9668f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 1=1Gb", EMLXS_CFG_HELP_SIZE);
967fcf3ce44SJohn Forte 		hi = 1;
968fcf3ce44SJohn Forte 	}
969291a2b48SSukumar Swaminathan 
970fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
9718f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 2=2Gb", EMLXS_CFG_HELP_SIZE);
972fcf3ce44SJohn Forte 		hi = 2;
973fcf3ce44SJohn Forte 	}
974291a2b48SSukumar Swaminathan 
975fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
9768f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 4=4Gb", EMLXS_CFG_HELP_SIZE);
977fcf3ce44SJohn Forte 		hi = 4;
978fcf3ce44SJohn Forte 	}
979291a2b48SSukumar Swaminathan 
980fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
9818f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 8=8Gb", EMLXS_CFG_HELP_SIZE);
982fcf3ce44SJohn Forte 		hi = 8;
983fcf3ce44SJohn Forte 	}
984291a2b48SSukumar Swaminathan 
985fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
9868f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 10=10Gb", EMLXS_CFG_HELP_SIZE);
987fcf3ce44SJohn Forte 		hi = 10;
988fcf3ce44SJohn Forte 	}
989291a2b48SSukumar Swaminathan 
9908f23e9faSHans Rosenfeld 	if (vpd->link_speed & LMT_16GB_CAPABLE) {
9918f23e9faSHans Rosenfeld 		(void) strlcat(cfg->help, ", 16=16Gb", EMLXS_CFG_HELP_SIZE);
9928f23e9faSHans Rosenfeld 		hi = 16;
9938f23e9faSHans Rosenfeld 	}
9948f23e9faSHans Rosenfeld 
995*a3170057SPaul Winder 	if (vpd->link_speed & LMT_32GB_CAPABLE) {
996*a3170057SPaul Winder 		(void) strlcat(cfg->help, ", 32=32Gb", EMLXS_CFG_HELP_SIZE);
997*a3170057SPaul Winder 		hi = 32;
998*a3170057SPaul Winder 	}
999*a3170057SPaul Winder 
10008f23e9faSHans Rosenfeld 	(void) strlcat(cfg->help, "]", EMLXS_CFG_HELP_SIZE);
1001fcf3ce44SJohn Forte 	cfg->hi = hi;
1002fcf3ce44SJohn Forte 
1003fcf3ce44SJohn Forte 	/* Now revalidate the current parameter setting */
1004fcf3ce44SJohn Forte 	cfg->current = emlxs_check_parm(hba, CFG_LINK_SPEED, cfg->current);
1005fcf3ce44SJohn Forte 
1006fcf3ce44SJohn Forte 	return;
1007fcf3ce44SJohn Forte 
100882527734SSukumar Swaminathan } /* emlxs_process_link_speed() */
1009fcf3ce44SJohn Forte 
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte /*
1012291a2b48SSukumar Swaminathan  * emlxs_parse_vpd()
1013fcf3ce44SJohn Forte  *
1014fcf3ce44SJohn Forte  * This routine will parse the VPD data
1015fcf3ce44SJohn Forte  */
1016fcf3ce44SJohn Forte extern int
1017fcf3ce44SJohn Forte emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd_buf, uint32_t size)
1018fcf3ce44SJohn Forte {
1019fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1020fcf3ce44SJohn Forte 	char tag[3];
1021fcf3ce44SJohn Forte 	uint8_t lenlo, lenhi;
1022fcf3ce44SJohn Forte 	uint32_t n;
1023fcf3ce44SJohn Forte 	uint16_t block_size;
1024fcf3ce44SJohn Forte 	uint32_t block_index = 0;
1025fcf3ce44SJohn Forte 	uint8_t sub_size;
1026fcf3ce44SJohn Forte 	uint32_t sub_index;
1027fcf3ce44SJohn Forte 	int32_t finished = 0;
1028fcf3ce44SJohn Forte 	int32_t index = 0;
1029fcf3ce44SJohn Forte 	char buffer[128];
1030fcf3ce44SJohn Forte 	emlxs_vpd_t *vpd;
1031fcf3ce44SJohn Forte 
1032fcf3ce44SJohn Forte 	vpd = &VPD;
1033fcf3ce44SJohn Forte 
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte 	while (!finished && (block_index < size)) {
1036fcf3ce44SJohn Forte 		/*
1037291a2b48SSukumar Swaminathan 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1038291a2b48SSukumar Swaminathan 		 *    "block_index = %x", block_index);
1039fcf3ce44SJohn Forte 		 */
1040fcf3ce44SJohn Forte 
1041fcf3ce44SJohn Forte 		switch (vpd_buf[block_index]) {
1042fcf3ce44SJohn Forte 		case 0x82:
1043fcf3ce44SJohn Forte 			index = block_index;
1044fcf3ce44SJohn Forte 			index += 1;
1045fcf3ce44SJohn Forte 			lenlo = vpd_buf[index];
1046fcf3ce44SJohn Forte 			index += 1;
1047fcf3ce44SJohn Forte 			lenhi = vpd_buf[index];
1048fcf3ce44SJohn Forte 			index += 1;
1049fcf3ce44SJohn Forte 			block_index = index;
1050fcf3ce44SJohn Forte 
1051fcf3ce44SJohn Forte 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1052fcf3ce44SJohn Forte 			block_index += block_size;
1053fcf3ce44SJohn Forte 
1054fcf3ce44SJohn Forte 			/*
1055fcf3ce44SJohn Forte 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1056291a2b48SSukumar Swaminathan 			 *    "block_size = %x", block_size);
1057fcf3ce44SJohn Forte 			 */
1058fcf3ce44SJohn Forte 
1059fcf3ce44SJohn Forte 			n = sizeof (buffer);
1060fcf3ce44SJohn Forte 			bzero(buffer, n);
1061fcf3ce44SJohn Forte 			bcopy(&vpd_buf[index], buffer,
1062fcf3ce44SJohn Forte 			    (block_size < (n - 1)) ? block_size : (n - 1));
1063fcf3ce44SJohn Forte 
10648f23e9faSHans Rosenfeld 			(void) strncpy(vpd->id, buffer, (sizeof (vpd->id)-1));
1065291a2b48SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "ID: %s",
1066291a2b48SSukumar Swaminathan 			    vpd->id);
1067fcf3ce44SJohn Forte 
1068fcf3ce44SJohn Forte 			break;
1069fcf3ce44SJohn Forte 
1070fcf3ce44SJohn Forte 		case 0x90:
1071fcf3ce44SJohn Forte 			index = block_index;
1072fcf3ce44SJohn Forte 			index += 1;
1073fcf3ce44SJohn Forte 			lenlo = vpd_buf[index];
1074fcf3ce44SJohn Forte 			index += 1;
1075fcf3ce44SJohn Forte 			lenhi = vpd_buf[index];
1076fcf3ce44SJohn Forte 			index += 1;
1077fcf3ce44SJohn Forte 			block_index = index;
1078fcf3ce44SJohn Forte 			sub_index = index;
1079fcf3ce44SJohn Forte 
1080fcf3ce44SJohn Forte 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1081fcf3ce44SJohn Forte 			block_index += block_size;
1082fcf3ce44SJohn Forte 
1083fcf3ce44SJohn Forte 			/*
1084fcf3ce44SJohn Forte 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1085291a2b48SSukumar Swaminathan 			 *    "block_size = %x", block_size);
1086fcf3ce44SJohn Forte 			 */
1087fcf3ce44SJohn Forte 
1088fcf3ce44SJohn Forte 			/* Scan for sub-blocks */
1089fcf3ce44SJohn Forte 			while ((sub_index < block_index) &&
1090fcf3ce44SJohn Forte 			    (sub_index < size)) {
1091fcf3ce44SJohn Forte 				/*
1092fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1093291a2b48SSukumar Swaminathan 				 *    "sub_index = %x", sub_index);
1094fcf3ce44SJohn Forte 				 */
1095fcf3ce44SJohn Forte 
1096fcf3ce44SJohn Forte 				index = sub_index;
1097fcf3ce44SJohn Forte 				tag[0] = vpd_buf[index++];
1098fcf3ce44SJohn Forte 				tag[1] = vpd_buf[index++];
1099fcf3ce44SJohn Forte 				tag[2] = 0;
1100fcf3ce44SJohn Forte 				sub_size = vpd_buf[index++];
1101fcf3ce44SJohn Forte 
1102fcf3ce44SJohn Forte 				/*
1103fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1104291a2b48SSukumar Swaminathan 				 *    "sub_size = %x", sub_size);
1105fcf3ce44SJohn Forte 				 */
1106fcf3ce44SJohn Forte 
1107fcf3ce44SJohn Forte 				sub_index = (index + sub_size);
1108fcf3ce44SJohn Forte 
1109fcf3ce44SJohn Forte 				n = sizeof (buffer);
1110fcf3ce44SJohn Forte 				bzero(buffer, n);
1111fcf3ce44SJohn Forte 				bcopy(&vpd_buf[index], buffer,
1112fcf3ce44SJohn Forte 				    (sub_size < (n - 1)) ? sub_size : (n - 1));
1113fcf3ce44SJohn Forte 
1114fcf3ce44SJohn Forte 				/*
1115fcf3ce44SJohn Forte 				 * Look for Engineering Change (EC)
1116fcf3ce44SJohn Forte 				 */
1117fcf3ce44SJohn Forte 				if (strcmp(tag, "EC") == 0) {
11188f23e9faSHans Rosenfeld 					(void) strncpy(vpd->eng_change, buffer,
11198f23e9faSHans Rosenfeld 					    (sizeof (vpd->eng_change)-1));
1120fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1121291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "EC: %s",
1122291a2b48SSukumar Swaminathan 					    vpd->eng_change);
1123fcf3ce44SJohn Forte 				}
1124fcf3ce44SJohn Forte 				/*
1125fcf3ce44SJohn Forte 				 * Look for Manufacturer (MN)
1126fcf3ce44SJohn Forte 				 */
1127fcf3ce44SJohn Forte 				else if (strcmp(tag, "MN") == 0) {
11288f23e9faSHans Rosenfeld 					(void) strncpy(vpd->manufacturer,
11298f23e9faSHans Rosenfeld 					    buffer,
11308f23e9faSHans Rosenfeld 					    (sizeof (vpd->manufacturer)-1));
1131fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1132291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "MN: %s",
1133291a2b48SSukumar Swaminathan 					    vpd->manufacturer);
1134fcf3ce44SJohn Forte 				}
1135fcf3ce44SJohn Forte 				/*
1136fcf3ce44SJohn Forte 				 * Look for Serial Number (SN)
1137fcf3ce44SJohn Forte 				 */
1138fcf3ce44SJohn Forte 				else if (strcmp(tag, "SN") == 0) {
11398f23e9faSHans Rosenfeld 					(void) strncpy(vpd->serial_num, buffer,
11408f23e9faSHans Rosenfeld 					    (sizeof (vpd->serial_num)-1));
1141fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1142291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "SN: %s",
1143291a2b48SSukumar Swaminathan 					    vpd->serial_num);
1144fcf3ce44SJohn Forte 
1145fcf3ce44SJohn Forte 					/* Validate the serial number */
1146291a2b48SSukumar Swaminathan 					if (strncmp(buffer, "FFFFFFFFFF", 10) ==
1147291a2b48SSukumar Swaminathan 					    0 ||
1148291a2b48SSukumar Swaminathan 					    strncmp(buffer, "0000000000", 10) ==
1149291a2b48SSukumar Swaminathan 					    0) {
1150fcf3ce44SJohn Forte 						vpd->serial_num[0] = 0;
1151fcf3ce44SJohn Forte 					}
1152fcf3ce44SJohn Forte 				}
1153fcf3ce44SJohn Forte 				/*
1154fcf3ce44SJohn Forte 				 * Look for Part Number (PN)
1155fcf3ce44SJohn Forte 				 */
1156fcf3ce44SJohn Forte 				else if (strcmp(tag, "PN") == 0) {
11578f23e9faSHans Rosenfeld 					(void) strncpy(vpd->part_num, buffer,
11588f23e9faSHans Rosenfeld 					    (sizeof (vpd->part_num)-1));
1159fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1160291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "PN: %s",
1161291a2b48SSukumar Swaminathan 					    vpd->part_num);
1162fcf3ce44SJohn Forte 				}
1163fcf3ce44SJohn Forte 				/*
1164fcf3ce44SJohn Forte 				 * Look for (V0)
1165fcf3ce44SJohn Forte 				 */
1166fcf3ce44SJohn Forte 				else if (strcmp(tag, "V0") == 0) {
1167fcf3ce44SJohn Forte 					/* Not used */
1168fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1169291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "V0: %s", buffer);
1170fcf3ce44SJohn Forte 				}
1171fcf3ce44SJohn Forte 				/*
1172fcf3ce44SJohn Forte 				 * Look for model description (V1)
1173fcf3ce44SJohn Forte 				 */
1174fcf3ce44SJohn Forte 				else if (strcmp(tag, "V1") == 0) {
11758f23e9faSHans Rosenfeld 					(void) strncpy(vpd->model_desc, buffer,
11768f23e9faSHans Rosenfeld 					    (sizeof (vpd->model_desc)-1));
1177fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1178291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Desc: %s",
1179291a2b48SSukumar Swaminathan 					    vpd->model_desc);
1180fcf3ce44SJohn Forte 				}
1181fcf3ce44SJohn Forte 				/*
1182fcf3ce44SJohn Forte 				 * Look for model (V2)
1183fcf3ce44SJohn Forte 				 */
1184fcf3ce44SJohn Forte 				else if (strcmp(tag, "V2") == 0) {
11858f23e9faSHans Rosenfeld 					(void) strncpy(vpd->model, buffer,
11868f23e9faSHans Rosenfeld 					    (sizeof (vpd->model)-1));
1187fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1188291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Model: %s",
1189291a2b48SSukumar Swaminathan 					    vpd->model);
1190fcf3ce44SJohn Forte 				}
1191fcf3ce44SJohn Forte 				/*
1192fcf3ce44SJohn Forte 				 * Look for program type (V3)
1193fcf3ce44SJohn Forte 				 */
1194fcf3ce44SJohn Forte 
1195fcf3ce44SJohn Forte 				else if (strcmp(tag, "V3") == 0) {
11968f23e9faSHans Rosenfeld 					(void) strncpy(vpd->prog_types,
11978f23e9faSHans Rosenfeld 					    buffer,
11988f23e9faSHans Rosenfeld 					    (sizeof (vpd->prog_types)-1));
1199fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1200291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Prog Types: %s",
1201291a2b48SSukumar Swaminathan 					    vpd->prog_types);
1202fcf3ce44SJohn Forte 				}
1203fcf3ce44SJohn Forte 				/*
1204fcf3ce44SJohn Forte 				 * Look for port number (V4)
1205fcf3ce44SJohn Forte 				 */
1206fcf3ce44SJohn Forte 				else if (strcmp(tag, "V4") == 0) {
12078f23e9faSHans Rosenfeld 					(void) strncpy(vpd->port_num, buffer,
12088f23e9faSHans Rosenfeld 					    (sizeof (vpd->port_num)-1));
1209fcf3ce44SJohn Forte 					vpd->port_index =
1210fcf3ce44SJohn Forte 					    emlxs_strtol(vpd->port_num, 10);
1211fcf3ce44SJohn Forte 
1212fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1213291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Port: %s",
1214291a2b48SSukumar Swaminathan 					    (vpd->port_num[0]) ? vpd->
1215291a2b48SSukumar Swaminathan 					    port_num : "not applicable");
1216fcf3ce44SJohn Forte 				}
1217fcf3ce44SJohn Forte 				/*
1218fcf3ce44SJohn Forte 				 * Look for checksum (RV)
1219fcf3ce44SJohn Forte 				 */
1220fcf3ce44SJohn Forte 				else if (strcmp(tag, "RV") == 0) {
1221fcf3ce44SJohn Forte 					/* Not used */
1222fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1223291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Checksum: 0x%x",
1224291a2b48SSukumar Swaminathan 					    buffer[0]);
1225291a2b48SSukumar Swaminathan 				}
1226291a2b48SSukumar Swaminathan 
1227291a2b48SSukumar Swaminathan 				else {
1228fcf3ce44SJohn Forte 					/* Generic */
1229fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1230291a2b48SSukumar Swaminathan 					    &emlxs_vpd_msg, "Tag: %s: %s",
1231291a2b48SSukumar Swaminathan 					    tag, buffer);
1232fcf3ce44SJohn Forte 				}
1233fcf3ce44SJohn Forte 			}
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 			break;
1236fcf3ce44SJohn Forte 
1237fcf3ce44SJohn Forte 		case 0x78:
1238fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "End Tag.");
1239fcf3ce44SJohn Forte 			finished = 1;
1240fcf3ce44SJohn Forte 			break;
1241fcf3ce44SJohn Forte 
1242fcf3ce44SJohn Forte 		default:
1243fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1244fcf3ce44SJohn Forte 			    "Unknown block: %x %x %x %x %x %x %x %x",
1245fcf3ce44SJohn Forte 			    vpd_buf[index], vpd_buf[index + 1],
1246fcf3ce44SJohn Forte 			    vpd_buf[index + 2], vpd_buf[index + 3],
1247fcf3ce44SJohn Forte 			    vpd_buf[index + 4], vpd_buf[index + 5],
1248fcf3ce44SJohn Forte 			    vpd_buf[index + 6], vpd_buf[index + 7]);
1249fcf3ce44SJohn Forte 			return (0);
1250fcf3ce44SJohn Forte 		}
1251fcf3ce44SJohn Forte 	}
1252fcf3ce44SJohn Forte 
1253fcf3ce44SJohn Forte 	return (1);
1254fcf3ce44SJohn Forte 
125582527734SSukumar Swaminathan } /* emlxs_parse_vpd */
125682527734SSukumar Swaminathan 
125782527734SSukumar Swaminathan 
125882527734SSukumar Swaminathan /*
125982527734SSukumar Swaminathan  * emlxs_parse_fcoe()
126082527734SSukumar Swaminathan  *
126182527734SSukumar Swaminathan  * This routine will parse the VPD data
126282527734SSukumar Swaminathan  */
126382527734SSukumar Swaminathan extern int
126482527734SSukumar Swaminathan emlxs_parse_fcoe(emlxs_hba_t *hba, uint8_t *fcoep, uint32_t size)
126582527734SSukumar Swaminathan {
126682527734SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
126782527734SSukumar Swaminathan 	tlv_fcoe_t *fcoelist;
126882527734SSukumar Swaminathan 	tlv_fcfconnectlist_t *fcflist;
126982527734SSukumar Swaminathan 	int i;
12708f23e9faSHans Rosenfeld 	uint32_t flags;
12718f23e9faSHans Rosenfeld 	uint32_t entry_count;
12728f23e9faSHans Rosenfeld 	char FabricName[32];
12738f23e9faSHans Rosenfeld 	char SwitchName[32];
127482527734SSukumar Swaminathan 
127582527734SSukumar Swaminathan 	/* Validate the config region 23 signature */
127682527734SSukumar Swaminathan 	if ((*fcoep != 'R') || (*(fcoep+1) != 'G') ||
127782527734SSukumar Swaminathan 	    (*(fcoep+2) != '2') || (*(fcoep+3) != '3')) {
127882527734SSukumar Swaminathan 		return (0);
127982527734SSukumar Swaminathan 	}
128082527734SSukumar Swaminathan 
128182527734SSukumar Swaminathan 	/* Search the config region 23, for FCOE Parameters record */
128282527734SSukumar Swaminathan 	i = 4;
128382527734SSukumar Swaminathan 	while ((i < size) && (*(fcoep+i) != 0xA0) && (*(fcoep+i) != 0xff)) {
128482527734SSukumar Swaminathan 		i += fcoep[i+1] * sizeof (uint32_t) + 2;
128582527734SSukumar Swaminathan 	}
128682527734SSukumar Swaminathan 
128782527734SSukumar Swaminathan 	if (*(fcoep+i) == 0xA0) {
128882527734SSukumar Swaminathan 		fcoelist = (tlv_fcoe_t *)(fcoep+i);
128982527734SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
129082527734SSukumar Swaminathan 		    "Found FCOE Params (A0):%d  x%x",
129182527734SSukumar Swaminathan 		    fcoelist->length, fcoelist->fip_flags);
129282527734SSukumar Swaminathan 		bcopy((uint8_t *)fcoelist, (uint8_t *)&hba->sli.sli4.cfgFCOE,
129382527734SSukumar Swaminathan 		    sizeof (tlv_fcoe_t));
129482527734SSukumar Swaminathan 	}
129582527734SSukumar Swaminathan 
129682527734SSukumar Swaminathan 
129782527734SSukumar Swaminathan 	/* Search the config region 23, for FCF record */
129882527734SSukumar Swaminathan 	i = 4;
129982527734SSukumar Swaminathan 	while ((i < size) && (*(fcoep+i) != 0xA1) && (*(fcoep+i) != 0xff)) {
130082527734SSukumar Swaminathan 		i += fcoep[i+1] * sizeof (uint32_t) + 2;
130182527734SSukumar Swaminathan 	}
130282527734SSukumar Swaminathan 
130382527734SSukumar Swaminathan 	if (*(fcoep+i) == 0xA1) {
130482527734SSukumar Swaminathan 		fcflist = (tlv_fcfconnectlist_t *)(fcoep+i);
130582527734SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
130682527734SSukumar Swaminathan 		    "Found FCF ConnectList (A1):%d", fcflist->length);
13078f23e9faSHans Rosenfeld 
130882527734SSukumar Swaminathan 		bcopy((uint8_t *)fcflist, (uint8_t *)&hba->sli.sli4.cfgFCF,
130982527734SSukumar Swaminathan 		    sizeof (tlv_fcfconnectlist_t));
13108f23e9faSHans Rosenfeld 
13118f23e9faSHans Rosenfeld 		/* Display the list */
13128f23e9faSHans Rosenfeld 		entry_count = (hba->sli.sli4.cfgFCF.length *
13138f23e9faSHans Rosenfeld 		    sizeof (uint32_t)) / sizeof (tlv_fcfconnectentry_t);
13148f23e9faSHans Rosenfeld 
13158f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
13168f23e9faSHans Rosenfeld 		    "FCF List: %d entries", entry_count);
13178f23e9faSHans Rosenfeld 
13188f23e9faSHans Rosenfeld 		for (i = 0; i < entry_count; i++) {
13198f23e9faSHans Rosenfeld 			flags = *(uint32_t *)&hba->sli.sli4.cfgFCF.entry[i];
13208f23e9faSHans Rosenfeld 			(void) emlxs_wwn_xlate(FabricName, sizeof (FabricName),
13218f23e9faSHans Rosenfeld 			    hba->sli.sli4.cfgFCF.entry[i].FabricName);
13228f23e9faSHans Rosenfeld 			(void) emlxs_wwn_xlate(SwitchName, sizeof (SwitchName),
13238f23e9faSHans Rosenfeld 			    hba->sli.sli4.cfgFCF.entry[i].SwitchName);
13248f23e9faSHans Rosenfeld 
13258f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
13268f23e9faSHans Rosenfeld 			    "FCF List:%02d %08x %s %s",
13278f23e9faSHans Rosenfeld 			    i, flags, FabricName, SwitchName);
13288f23e9faSHans Rosenfeld 		}
132982527734SSukumar Swaminathan 	}
133082527734SSukumar Swaminathan 
133182527734SSukumar Swaminathan 	return (1);
133282527734SSukumar Swaminathan 
133382527734SSukumar Swaminathan } /* emlxs_parse_fcoe */
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 
1336fcf3ce44SJohn Forte extern void
1337fcf3ce44SJohn Forte emlxs_decode_firmware_rev(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1338fcf3ce44SJohn Forte {
1339fcf3ce44SJohn Forte 	if (vpd->rBit) {
1340fcf3ce44SJohn Forte 		switch (hba->sli_mode) {
1341291a2b48SSukumar Swaminathan 		case EMLXS_HBA_SLI4_MODE:
13428f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_version, vpd->sli4FwName,
13438f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_version)-1));
13448f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_label, vpd->sli4FwLabel,
13458f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_label)-1));
1346fcf3ce44SJohn Forte 			break;
1347291a2b48SSukumar Swaminathan 		case EMLXS_HBA_SLI3_MODE:
13488f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_version, vpd->sli3FwName,
13498f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_version)-1));
13508f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_label, vpd->sli3FwLabel,
13518f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_label)-1));
1352fcf3ce44SJohn Forte 			break;
1353291a2b48SSukumar Swaminathan 		case EMLXS_HBA_SLI2_MODE:
13548f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_version, vpd->sli2FwName,
13558f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_version)-1));
13568f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_label, vpd->sli2FwLabel,
13578f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_label)-1));
1358fcf3ce44SJohn Forte 			break;
1359291a2b48SSukumar Swaminathan 		case EMLXS_HBA_SLI1_MODE:
13608f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_version, vpd->sli1FwName,
13618f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_version)-1));
13628f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_label, vpd->sli1FwLabel,
13638f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_label)-1));
1364fcf3ce44SJohn Forte 			break;
1365fcf3ce44SJohn Forte 		default:
13668f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_version, "unknown",
13678f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_version)-1));
13688f23e9faSHans Rosenfeld 			(void) strncpy(vpd->fw_label, vpd->fw_version,
13698f23e9faSHans Rosenfeld 			    (sizeof (vpd->fw_label)-1));
1370fcf3ce44SJohn Forte 		}
1371fcf3ce44SJohn Forte 	} else {
13728f23e9faSHans Rosenfeld 		emlxs_decode_version(vpd->smFwRev, vpd->fw_version,
13738f23e9faSHans Rosenfeld 		    sizeof (vpd->fw_version));
13748f23e9faSHans Rosenfeld 		(void) strncpy(vpd->fw_label, vpd->fw_version,
13758f23e9faSHans Rosenfeld 		    (sizeof (vpd->fw_label)-1));
1376fcf3ce44SJohn Forte 	}
1377fcf3ce44SJohn Forte 
1378fcf3ce44SJohn Forte 	return;
1379fcf3ce44SJohn Forte 
138082527734SSukumar Swaminathan } /* emlxs_decode_firmware_rev() */
1381fcf3ce44SJohn Forte 
1382fcf3ce44SJohn Forte 
1383fcf3ce44SJohn Forte 
1384fcf3ce44SJohn Forte extern void
13858f23e9faSHans Rosenfeld emlxs_decode_version(uint32_t version, char *buffer, size_t len)
1386fcf3ce44SJohn Forte {
1387fcf3ce44SJohn Forte 	uint32_t b1, b2, b3, b4;
1388fcf3ce44SJohn Forte 	char c;
1389fcf3ce44SJohn Forte 
1390fcf3ce44SJohn Forte 	b1 = (version & 0x0000f000) >> 12;
1391fcf3ce44SJohn Forte 	b2 = (version & 0x00000f00) >> 8;
1392fcf3ce44SJohn Forte 	b3 = (version & 0x000000c0) >> 6;
1393fcf3ce44SJohn Forte 	b4 = (version & 0x00000030) >> 4;
1394fcf3ce44SJohn Forte 
1395fcf3ce44SJohn Forte 	if (b1 == 0 && b2 == 0) {
13968f23e9faSHans Rosenfeld 		(void) snprintf(buffer, len, "none");
1397fcf3ce44SJohn Forte 		return;
1398fcf3ce44SJohn Forte 	}
1399291a2b48SSukumar Swaminathan 
1400fcf3ce44SJohn Forte 	c = 0;
1401fcf3ce44SJohn Forte 	switch (b4) {
1402fcf3ce44SJohn Forte 	case 0:
1403fcf3ce44SJohn Forte 		c = 'n';
1404fcf3ce44SJohn Forte 		break;
1405fcf3ce44SJohn Forte 	case 1:
1406fcf3ce44SJohn Forte 		c = 'a';
1407fcf3ce44SJohn Forte 		break;
1408fcf3ce44SJohn Forte 	case 2:
1409fcf3ce44SJohn Forte 		c = 'b';
1410fcf3ce44SJohn Forte 		break;
1411fcf3ce44SJohn Forte 	case 3:
1412fcf3ce44SJohn Forte 		if ((version & 0x0000000f)) {
1413fcf3ce44SJohn Forte 			c = 'x';
1414fcf3ce44SJohn Forte 		}
1415fcf3ce44SJohn Forte 		break;
1416fcf3ce44SJohn Forte 
1417fcf3ce44SJohn Forte 	}
1418fcf3ce44SJohn Forte 	b4 = (version & 0x0000000f);
1419fcf3ce44SJohn Forte 
1420fcf3ce44SJohn Forte 	if (c == 0) {
14218f23e9faSHans Rosenfeld 		(void) snprintf(buffer, len, "%d.%d%d", b1, b2, b3);
1422fcf3ce44SJohn Forte 	} else {
14238f23e9faSHans Rosenfeld 		(void) snprintf(buffer, len, "%d.%d%d%c%d", b1, b2, b3, c, b4);
1424fcf3ce44SJohn Forte 	}
1425fcf3ce44SJohn Forte 
1426fcf3ce44SJohn Forte 	return;
1427fcf3ce44SJohn Forte 
142882527734SSukumar Swaminathan } /* emlxs_decode_version() */
1429fcf3ce44SJohn Forte 
1430fcf3ce44SJohn Forte 
143182527734SSukumar Swaminathan extern void
14328f23e9faSHans Rosenfeld emlxs_decode_label(char *label, char *buffer, int bige, size_t len)
1433fcf3ce44SJohn Forte {
1434fcf3ce44SJohn Forte 	uint32_t i;
1435fcf3ce44SJohn Forte 	char name[16];
1436fcf3ce44SJohn Forte 
14378f23e9faSHans Rosenfeld 	bzero(name, sizeof (name));
14388f23e9faSHans Rosenfeld 	bcopy(label, name, MIN(sizeof (name), len));
143982527734SSukumar Swaminathan 	/* bige is TRUE if the data format is big endian */
1440fcf3ce44SJohn Forte 
144182527734SSukumar Swaminathan 	if (bige) {
144282527734SSukumar Swaminathan 		/* Data format big Endian */
144382527734SSukumar Swaminathan 		LE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
144482527734SSukumar Swaminathan 
144582527734SSukumar Swaminathan 		for (i = 0; i < sizeof (name); i++) {
144682527734SSukumar Swaminathan 			if (name[i] == 0x20) {
144782527734SSukumar Swaminathan 				name[i] = 0;
144882527734SSukumar Swaminathan 			}
144982527734SSukumar Swaminathan 		}
145082527734SSukumar Swaminathan 	} else {
145182527734SSukumar Swaminathan 		/* Data format little Endian */
145282527734SSukumar Swaminathan 		BE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
1453fcf3ce44SJohn Forte 
145482527734SSukumar Swaminathan 		for (i = 0; i < sizeof (name); i++) {
145582527734SSukumar Swaminathan 			if (name[i] == 0x20) {
145682527734SSukumar Swaminathan 				name[i] = 0;
145782527734SSukumar Swaminathan 			}
1458fcf3ce44SJohn Forte 		}
1459fcf3ce44SJohn Forte 	}
1460fcf3ce44SJohn Forte 
14618f23e9faSHans Rosenfeld 	(void) strlcpy(buffer, name, len);
1462fcf3ce44SJohn Forte 
1463fcf3ce44SJohn Forte 	return;
1464fcf3ce44SJohn Forte 
146582527734SSukumar Swaminathan } /* emlxs_decode_label() */
1466fcf3ce44SJohn Forte 
1467fcf3ce44SJohn Forte 
1468fcf3ce44SJohn Forte extern uint32_t
1469fcf3ce44SJohn Forte emlxs_strtol(char *str, uint32_t base)
1470fcf3ce44SJohn Forte {
1471fcf3ce44SJohn Forte 	uint32_t value = 0;
1472fcf3ce44SJohn Forte 	char *ptr;
1473fcf3ce44SJohn Forte 	uint32_t factor = 1;
1474fcf3ce44SJohn Forte 	uint32_t digits;
1475fcf3ce44SJohn Forte 
1476fcf3ce44SJohn Forte 	if (*str == 0) {
1477fcf3ce44SJohn Forte 		return (0);
1478fcf3ce44SJohn Forte 	}
1479291a2b48SSukumar Swaminathan 
1480fcf3ce44SJohn Forte 	if (base != 10 && base != 16) {
1481fcf3ce44SJohn Forte 		return (0);
1482fcf3ce44SJohn Forte 	}
1483291a2b48SSukumar Swaminathan 
1484fcf3ce44SJohn Forte 	/* Get max digits of value */
1485fcf3ce44SJohn Forte 	digits = (base == 10) ? 9 : 8;
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte 	/* Position pointer to end of string */
1488fcf3ce44SJohn Forte 	ptr = str + strlen(str);
1489fcf3ce44SJohn Forte 
1490fcf3ce44SJohn Forte 	/* Process string backwards */
1491fcf3ce44SJohn Forte 	while ((ptr-- > str) && digits) {
1492fcf3ce44SJohn Forte 		/* check for base 10 numbers */
1493fcf3ce44SJohn Forte 		if (*ptr >= '0' && *ptr <= '9') {
1494fcf3ce44SJohn Forte 			value += ((uint32_t)(*ptr - '0')) * factor;
1495fcf3ce44SJohn Forte 			factor *= base;
1496fcf3ce44SJohn Forte 			digits--;
1497fcf3ce44SJohn Forte 		} else if (base == 16) {
1498fcf3ce44SJohn Forte 			/* Check for base 16 numbers */
1499fcf3ce44SJohn Forte 			if (*ptr >= 'a' && *ptr <= 'f') {
1500291a2b48SSukumar Swaminathan 				value +=
1501291a2b48SSukumar Swaminathan 				    ((uint32_t)(*ptr - 'a') + 10) * factor;
1502fcf3ce44SJohn Forte 				factor *= base;
1503fcf3ce44SJohn Forte 				digits--;
1504fcf3ce44SJohn Forte 			} else if (*ptr >= 'A' && *ptr <= 'F') {
1505291a2b48SSukumar Swaminathan 				value +=
1506291a2b48SSukumar Swaminathan 				    ((uint32_t)(*ptr - 'A') + 10) * factor;
1507fcf3ce44SJohn Forte 				factor *= base;
1508fcf3ce44SJohn Forte 				digits--;
1509fcf3ce44SJohn Forte 			} else if (factor > 1) {
1510fcf3ce44SJohn Forte 				break;
1511fcf3ce44SJohn Forte 			}
1512fcf3ce44SJohn Forte 		} else if (factor > 1) {
1513fcf3ce44SJohn Forte 			break;
1514fcf3ce44SJohn Forte 		}
1515fcf3ce44SJohn Forte 	}
1516fcf3ce44SJohn Forte 
1517fcf3ce44SJohn Forte 	return (value);
1518fcf3ce44SJohn Forte 
151982527734SSukumar Swaminathan } /* emlxs_strtol() */
1520fcf3ce44SJohn Forte 
1521fcf3ce44SJohn Forte 
1522fcf3ce44SJohn Forte extern uint64_t
1523fcf3ce44SJohn Forte emlxs_strtoll(char *str, uint32_t base)
1524fcf3ce44SJohn Forte {
1525fcf3ce44SJohn Forte 	uint64_t value = 0;
1526fcf3ce44SJohn Forte 	char *ptr;
1527fcf3ce44SJohn Forte 	uint32_t factor = 1;
1528fcf3ce44SJohn Forte 	uint32_t digits;
1529fcf3ce44SJohn Forte 
1530fcf3ce44SJohn Forte 	if (*str == 0) {
1531fcf3ce44SJohn Forte 		return (0);
1532fcf3ce44SJohn Forte 	}
1533291a2b48SSukumar Swaminathan 
1534fcf3ce44SJohn Forte 	if (base != 10 && base != 16) {
1535fcf3ce44SJohn Forte 		return (0);
1536fcf3ce44SJohn Forte 	}
1537291a2b48SSukumar Swaminathan 
1538fcf3ce44SJohn Forte 	/* Get max digits of value */
1539fcf3ce44SJohn Forte 	digits = (base == 10) ? 19 : 16;
1540fcf3ce44SJohn Forte 
1541fcf3ce44SJohn Forte 	/* Position pointer to end of string */
1542fcf3ce44SJohn Forte 	ptr = str + strlen(str);
1543fcf3ce44SJohn Forte 
1544fcf3ce44SJohn Forte 	/* Process string backwards */
1545fcf3ce44SJohn Forte 	while ((ptr-- > str) && digits) {
1546fcf3ce44SJohn Forte 		/* check for base 10 numbers */
1547fcf3ce44SJohn Forte 		if (*ptr >= '0' && *ptr <= '9') {
1548fcf3ce44SJohn Forte 			value += ((uint32_t)(*ptr - '0')) * factor;
1549fcf3ce44SJohn Forte 			factor *= base;
1550fcf3ce44SJohn Forte 			digits--;
1551fcf3ce44SJohn Forte 		} else if (base == 16) {
1552fcf3ce44SJohn Forte 			/* Check for base 16 numbers */
1553fcf3ce44SJohn Forte 			if (*ptr >= 'a' && *ptr <= 'f') {
1554291a2b48SSukumar Swaminathan 				value +=
1555291a2b48SSukumar Swaminathan 				    ((uint32_t)(*ptr - 'a') + 10) * factor;
1556fcf3ce44SJohn Forte 				factor *= base;
1557fcf3ce44SJohn Forte 				digits--;
1558fcf3ce44SJohn Forte 			} else if (*ptr >= 'A' && *ptr <= 'F') {
1559291a2b48SSukumar Swaminathan 				value +=
1560291a2b48SSukumar Swaminathan 				    ((uint32_t)(*ptr - 'A') + 10) * factor;
1561fcf3ce44SJohn Forte 				factor *= base;
1562fcf3ce44SJohn Forte 				digits--;
1563fcf3ce44SJohn Forte 			} else if (factor > 1) {
1564fcf3ce44SJohn Forte 				break;
1565fcf3ce44SJohn Forte 			}
1566fcf3ce44SJohn Forte 		} else if (factor > 1) {
1567fcf3ce44SJohn Forte 			break;
1568fcf3ce44SJohn Forte 		}
1569fcf3ce44SJohn Forte 	}
1570fcf3ce44SJohn Forte 
1571fcf3ce44SJohn Forte 	return (value);
1572fcf3ce44SJohn Forte 
157382527734SSukumar Swaminathan } /* emlxs_strtoll() */
1574fcf3ce44SJohn Forte 
157582527734SSukumar Swaminathan extern void
1576fcf3ce44SJohn Forte emlxs_parse_prog_types(emlxs_hba_t *hba, char *prog_types)
1577fcf3ce44SJohn Forte {
1578fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1579fcf3ce44SJohn Forte 	uint32_t i;
1580fcf3ce44SJohn Forte 	char *ptr;
1581fcf3ce44SJohn Forte 	emlxs_model_t *model;
1582fcf3ce44SJohn Forte 	char types_buffer[256];
1583fcf3ce44SJohn Forte 	char *types;
1584fcf3ce44SJohn Forte 
1585fcf3ce44SJohn Forte 	bcopy(prog_types, types_buffer, 256);
1586fcf3ce44SJohn Forte 	types = types_buffer;
1587fcf3ce44SJohn Forte 
1588fcf3ce44SJohn Forte 	model = &hba->model_info;
1589fcf3ce44SJohn Forte 
1590fcf3ce44SJohn Forte 	while (*types) {
1591fcf3ce44SJohn Forte 		if (strncmp(types, "T2:", 3) == 0) {
1592fcf3ce44SJohn Forte 			bzero(model->pt_2, sizeof (model->pt_2));
1593fcf3ce44SJohn Forte 			types += 3;
1594fcf3ce44SJohn Forte 
1595fcf3ce44SJohn Forte 			i = 0;
1596fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1597fcf3ce44SJohn Forte 				/* Null terminate the next value */
1598fcf3ce44SJohn Forte 				ptr = types;
1599fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1600fcf3ce44SJohn Forte 					ptr++;
1601fcf3ce44SJohn Forte 				*ptr = 0;
1602fcf3ce44SJohn Forte 
1603fcf3ce44SJohn Forte 				/* Save the value */
1604fcf3ce44SJohn Forte 				model->pt_2[i++] =
1605fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1606fcf3ce44SJohn Forte 
1607fcf3ce44SJohn Forte 				/*
1608fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1609fcf3ce44SJohn Forte 				 * "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
1610fcf3ce44SJohn Forte 				 */
1611fcf3ce44SJohn Forte 
1612fcf3ce44SJohn Forte 				/* Move the str pointer */
1613fcf3ce44SJohn Forte 				types = ptr + 1;
1614fcf3ce44SJohn Forte 			}
1615fcf3ce44SJohn Forte 
1616fcf3ce44SJohn Forte 		} else if (strncmp(types, "T3:", 3) == 0) {
1617fcf3ce44SJohn Forte 			bzero(model->pt_3, sizeof (model->pt_3));
1618fcf3ce44SJohn Forte 			types += 3;
1619fcf3ce44SJohn Forte 
1620fcf3ce44SJohn Forte 			i = 0;
1621fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1622fcf3ce44SJohn Forte 				/* Null terminate the next value */
1623fcf3ce44SJohn Forte 				ptr = types;
1624fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1625fcf3ce44SJohn Forte 					ptr++;
1626fcf3ce44SJohn Forte 				*ptr = 0;
1627fcf3ce44SJohn Forte 
1628fcf3ce44SJohn Forte 				/* Save the value */
1629fcf3ce44SJohn Forte 				model->pt_3[i++] =
1630fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1631fcf3ce44SJohn Forte 
1632fcf3ce44SJohn Forte 				/*
1633fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1634fcf3ce44SJohn Forte 				 * "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
1635fcf3ce44SJohn Forte 				 */
1636fcf3ce44SJohn Forte 
1637fcf3ce44SJohn Forte 				/* Move the str pointer */
1638fcf3ce44SJohn Forte 				types = ptr + 1;
1639fcf3ce44SJohn Forte 			}
1640fcf3ce44SJohn Forte 		} else if (strncmp(types, "T6:", 3) == 0) {
1641fcf3ce44SJohn Forte 			bzero(model->pt_6, sizeof (model->pt_6));
1642fcf3ce44SJohn Forte 			types += 3;
1643fcf3ce44SJohn Forte 
1644fcf3ce44SJohn Forte 			i = 0;
1645fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1646fcf3ce44SJohn Forte 				/* Null terminate the next value */
1647fcf3ce44SJohn Forte 				ptr = types;
1648fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1649fcf3ce44SJohn Forte 					ptr++;
1650fcf3ce44SJohn Forte 				*ptr = 0;
1651fcf3ce44SJohn Forte 
1652fcf3ce44SJohn Forte 				/* Save the value */
1653fcf3ce44SJohn Forte 				model->pt_6[i++] =
1654fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1655fcf3ce44SJohn Forte 				model->pt_6[i] = 0;
1656fcf3ce44SJohn Forte 
1657fcf3ce44SJohn Forte 				/*
1658fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1659fcf3ce44SJohn Forte 				 * "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
1660fcf3ce44SJohn Forte 				 */
1661fcf3ce44SJohn Forte 
1662fcf3ce44SJohn Forte 				/* Move the str pointer */
1663fcf3ce44SJohn Forte 				types = ptr + 1;
1664fcf3ce44SJohn Forte 			}
1665fcf3ce44SJohn Forte 		} else if (strncmp(types, "T7:", 3) == 0) {
1666fcf3ce44SJohn Forte 			bzero(model->pt_7, sizeof (model->pt_7));
1667fcf3ce44SJohn Forte 			types += 3;
1668fcf3ce44SJohn Forte 
1669fcf3ce44SJohn Forte 			i = 0;
1670fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1671fcf3ce44SJohn Forte 				/* Null terminate the next value */
1672fcf3ce44SJohn Forte 				ptr = types;
1673fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1674fcf3ce44SJohn Forte 					ptr++;
1675fcf3ce44SJohn Forte 				*ptr = 0;
1676fcf3ce44SJohn Forte 
1677fcf3ce44SJohn Forte 				/* Save the value */
1678fcf3ce44SJohn Forte 				model->pt_7[i++] =
1679fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1680fcf3ce44SJohn Forte 				model->pt_7[i] = 0;
1681fcf3ce44SJohn Forte 
1682fcf3ce44SJohn Forte 				/*
1683fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1684fcf3ce44SJohn Forte 				 * "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
1685fcf3ce44SJohn Forte 				 */
1686fcf3ce44SJohn Forte 
1687fcf3ce44SJohn Forte 				/* Move the str pointer */
1688fcf3ce44SJohn Forte 				types = ptr + 1;
1689fcf3ce44SJohn Forte 			}
1690fcf3ce44SJohn Forte 		} else if (strncmp(types, "TA:", 3) == 0) {
1691fcf3ce44SJohn Forte 			bzero(model->pt_A, sizeof (model->pt_A));
1692fcf3ce44SJohn Forte 			types += 3;
1693fcf3ce44SJohn Forte 
1694fcf3ce44SJohn Forte 			i = 0;
1695fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1696fcf3ce44SJohn Forte 				/* Null terminate the next value */
1697fcf3ce44SJohn Forte 				ptr = types;
1698fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1699fcf3ce44SJohn Forte 					ptr++;
1700fcf3ce44SJohn Forte 				*ptr = 0;
1701fcf3ce44SJohn Forte 
1702fcf3ce44SJohn Forte 				/* Save the value */
1703fcf3ce44SJohn Forte 				model->pt_A[i++] =
1704fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1705fcf3ce44SJohn Forte 
1706fcf3ce44SJohn Forte 				/*
1707fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1708fcf3ce44SJohn Forte 				 * "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
1709fcf3ce44SJohn Forte 				 */
1710fcf3ce44SJohn Forte 
1711fcf3ce44SJohn Forte 				/* Move the str pointer */
1712fcf3ce44SJohn Forte 				types = ptr + 1;
1713fcf3ce44SJohn Forte 			}
1714fcf3ce44SJohn Forte 		} else if (strncmp(types, "TB:", 3) == 0) {
1715fcf3ce44SJohn Forte 			bzero(model->pt_B, sizeof (model->pt_B));
1716fcf3ce44SJohn Forte 			types += 3;
1717fcf3ce44SJohn Forte 
1718fcf3ce44SJohn Forte 			i = 0;
1719fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1720fcf3ce44SJohn Forte 				/* Null terminate the next value */
1721fcf3ce44SJohn Forte 				ptr = types;
1722fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1723fcf3ce44SJohn Forte 					ptr++;
1724fcf3ce44SJohn Forte 				*ptr = 0;
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte 				/* Save the value */
1727fcf3ce44SJohn Forte 				model->pt_B[i++] =
1728fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1729fcf3ce44SJohn Forte 
1730fcf3ce44SJohn Forte 				/*
1731fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1732fcf3ce44SJohn Forte 				 * "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
1733fcf3ce44SJohn Forte 				 */
1734fcf3ce44SJohn Forte 
1735fcf3ce44SJohn Forte 				/* Move the str pointer */
1736fcf3ce44SJohn Forte 				types = ptr + 1;
1737fcf3ce44SJohn Forte 			}
1738fcf3ce44SJohn Forte 		} else if (strncmp(types, "TFF:", 4) == 0) {
1739fcf3ce44SJohn Forte 			bzero(model->pt_FF, sizeof (model->pt_FF));
1740fcf3ce44SJohn Forte 			types += 4;
1741fcf3ce44SJohn Forte 
1742fcf3ce44SJohn Forte 			i = 0;
1743fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
1744fcf3ce44SJohn Forte 				/* Null terminate the next value */
1745fcf3ce44SJohn Forte 				ptr = types;
1746fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
1747fcf3ce44SJohn Forte 					ptr++;
1748fcf3ce44SJohn Forte 				*ptr = 0;
1749fcf3ce44SJohn Forte 
1750fcf3ce44SJohn Forte 				/* Save the value */
1751fcf3ce44SJohn Forte 				model->pt_FF[i++] =
1752fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
1753fcf3ce44SJohn Forte 
1754fcf3ce44SJohn Forte 				/*
1755fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1756fcf3ce44SJohn Forte 				 * "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
1757fcf3ce44SJohn Forte 				 */
1758fcf3ce44SJohn Forte 
1759291a2b48SSukumar Swaminathan 				/* Move the str pointer */
1760291a2b48SSukumar Swaminathan 				types = ptr + 1;
1761291a2b48SSukumar Swaminathan 			}
1762291a2b48SSukumar Swaminathan 		} else if (strncmp(types, "T20:", 4) == 0) {
1763291a2b48SSukumar Swaminathan 			bzero(model->pt_20, sizeof (model->pt_20));
1764291a2b48SSukumar Swaminathan 			types += 4;
1765291a2b48SSukumar Swaminathan 
1766291a2b48SSukumar Swaminathan 			i = 0;
1767291a2b48SSukumar Swaminathan 			while (*types && *types != 'T') {
1768291a2b48SSukumar Swaminathan 				/* Null terminate the next value */
1769291a2b48SSukumar Swaminathan 				ptr = types;
1770291a2b48SSukumar Swaminathan 				while (*ptr && (*ptr != ','))
1771291a2b48SSukumar Swaminathan 					ptr++;
1772291a2b48SSukumar Swaminathan 				*ptr = 0;
1773291a2b48SSukumar Swaminathan 
1774291a2b48SSukumar Swaminathan 				/* Save the value */
1775291a2b48SSukumar Swaminathan 				model->pt_20[i++] =
1776291a2b48SSukumar Swaminathan 				    (uint8_t)emlxs_strtol(types, 16);
1777291a2b48SSukumar Swaminathan 				model->pt_20[i] = 0;
1778291a2b48SSukumar Swaminathan 
1779291a2b48SSukumar Swaminathan 				/*
1780291a2b48SSukumar Swaminathan 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1781291a2b48SSukumar Swaminathan 				 * "T20[%d]: 0x%x", i-1, model->pt_20[i-1]);
1782291a2b48SSukumar Swaminathan 				 */
1783291a2b48SSukumar Swaminathan 
1784fcf3ce44SJohn Forte 				/* Move the str pointer */
1785fcf3ce44SJohn Forte 				types = ptr + 1;
1786fcf3ce44SJohn Forte 			}
1787fcf3ce44SJohn Forte 		} else {
1788fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1789fcf3ce44SJohn Forte 			    "Unknown prog type string = %s", types);
1790fcf3ce44SJohn Forte 			break;
1791fcf3ce44SJohn Forte 		}
1792fcf3ce44SJohn Forte 	}
1793fcf3ce44SJohn Forte 
1794fcf3ce44SJohn Forte 	return;
1795fcf3ce44SJohn Forte 
179682527734SSukumar Swaminathan } /* emlxs_parse_prog_types() */
1797fcf3ce44SJohn Forte 
1798fcf3ce44SJohn Forte 
179982527734SSukumar Swaminathan extern void
18008f23e9faSHans Rosenfeld emlxs_build_prog_types(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1801fcf3ce44SJohn Forte {
1802fcf3ce44SJohn Forte 	uint32_t i;
1803fcf3ce44SJohn Forte 	uint32_t found = 0;
1804fcf3ce44SJohn Forte 	char buffer[256];
1805fcf3ce44SJohn Forte 
18068f23e9faSHans Rosenfeld 	bzero(vpd->prog_types, sizeof (vpd->prog_types));
1807fcf3ce44SJohn Forte 
1808fcf3ce44SJohn Forte 	/* Rebuild the prog type string */
1809fcf3ce44SJohn Forte 	if (hba->model_info.pt_2[0]) {
18108f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "T2:",
18118f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1812fcf3ce44SJohn Forte 		found = 1;
1813fcf3ce44SJohn Forte 
1814fcf3ce44SJohn Forte 		i = 0;
18158f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_2[i])) {
18168f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18178f23e9faSHans Rosenfeld 			    hba->model_info.pt_2[i]);
18188f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18198f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1820fcf3ce44SJohn Forte 			i++;
1821fcf3ce44SJohn Forte 		}
1822fcf3ce44SJohn Forte 	}
1823291a2b48SSukumar Swaminathan 
1824fcf3ce44SJohn Forte 	if (hba->model_info.pt_3[0]) {
18258f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "T3:",
18268f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1827fcf3ce44SJohn Forte 		found = 1;
1828fcf3ce44SJohn Forte 
1829fcf3ce44SJohn Forte 		i = 0;
18308f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_3[i])) {
18318f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18328f23e9faSHans Rosenfeld 			    hba->model_info.pt_3[i]);
18338f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18348f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1835fcf3ce44SJohn Forte 			i++;
1836fcf3ce44SJohn Forte 
1837fcf3ce44SJohn Forte 		}
1838fcf3ce44SJohn Forte 	}
1839291a2b48SSukumar Swaminathan 
1840fcf3ce44SJohn Forte 	if (hba->model_info.pt_6[0]) {
18418f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "T6:",
18428f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1843fcf3ce44SJohn Forte 		found = 1;
1844fcf3ce44SJohn Forte 
1845fcf3ce44SJohn Forte 		i = 0;
18468f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_6[i])) {
18478f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18488f23e9faSHans Rosenfeld 			    hba->model_info.pt_6[i]);
18498f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18508f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1851fcf3ce44SJohn Forte 			i++;
1852fcf3ce44SJohn Forte 		}
1853fcf3ce44SJohn Forte 	}
1854291a2b48SSukumar Swaminathan 
1855fcf3ce44SJohn Forte 	if (hba->model_info.pt_7[0]) {
18568f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "T7:",
18578f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1858fcf3ce44SJohn Forte 		found = 1;
1859fcf3ce44SJohn Forte 
1860fcf3ce44SJohn Forte 		i = 0;
18618f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_7[i])) {
18628f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18638f23e9faSHans Rosenfeld 			    hba->model_info.pt_7[i]);
18648f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18658f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1866fcf3ce44SJohn Forte 			i++;
1867fcf3ce44SJohn Forte 		}
1868fcf3ce44SJohn Forte 	}
1869291a2b48SSukumar Swaminathan 
1870fcf3ce44SJohn Forte 	if (hba->model_info.pt_A[0]) {
18718f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "TA:",
18728f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1873fcf3ce44SJohn Forte 		found = 1;
1874fcf3ce44SJohn Forte 
1875fcf3ce44SJohn Forte 		i = 0;
18768f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_A[i])) {
18778f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18788f23e9faSHans Rosenfeld 			    hba->model_info.pt_A[i]);
18798f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18808f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1881fcf3ce44SJohn Forte 			i++;
1882fcf3ce44SJohn Forte 		}
1883fcf3ce44SJohn Forte 	}
1884291a2b48SSukumar Swaminathan 
1885291a2b48SSukumar Swaminathan 
1886fcf3ce44SJohn Forte 	if (hba->model_info.pt_B[0]) {
18878f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "TB:",
18888f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1889fcf3ce44SJohn Forte 		found = 1;
1890fcf3ce44SJohn Forte 
1891fcf3ce44SJohn Forte 		i = 0;
18928f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_B[i])) {
18938f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
18948f23e9faSHans Rosenfeld 			    hba->model_info.pt_B[i]);
18958f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
18968f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1897fcf3ce44SJohn Forte 			i++;
1898fcf3ce44SJohn Forte 		}
1899fcf3ce44SJohn Forte 	}
1900291a2b48SSukumar Swaminathan 
1901291a2b48SSukumar Swaminathan 	if (hba->model_info.pt_20[0]) {
19028f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "T20:",
19038f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1904291a2b48SSukumar Swaminathan 		found = 1;
1905291a2b48SSukumar Swaminathan 
1906291a2b48SSukumar Swaminathan 		i = 0;
19078f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_20[i])) {
19088f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
19098f23e9faSHans Rosenfeld 			    hba->model_info.pt_20[i]);
19108f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
19118f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1912291a2b48SSukumar Swaminathan 			i++;
1913291a2b48SSukumar Swaminathan 		}
1914291a2b48SSukumar Swaminathan 	}
1915291a2b48SSukumar Swaminathan 
1916fcf3ce44SJohn Forte 	if (hba->model_info.pt_FF[0]) {
19178f23e9faSHans Rosenfeld 		(void) strlcat(vpd->prog_types, "TFF:",
19188f23e9faSHans Rosenfeld 		    sizeof (vpd->prog_types));
1919fcf3ce44SJohn Forte 		found = 1;
1920fcf3ce44SJohn Forte 
1921fcf3ce44SJohn Forte 		i = 0;
19228f23e9faSHans Rosenfeld 		while ((i < 8) && (hba->model_info.pt_FF[i])) {
19238f23e9faSHans Rosenfeld 			(void) snprintf(buffer, sizeof (buffer), "%X,",
19248f23e9faSHans Rosenfeld 			    hba->model_info.pt_FF[i]);
19258f23e9faSHans Rosenfeld 			(void) strlcat(vpd->prog_types, buffer,
19268f23e9faSHans Rosenfeld 			    sizeof (vpd->prog_types));
1927fcf3ce44SJohn Forte 			i++;
1928fcf3ce44SJohn Forte 		}
1929fcf3ce44SJohn Forte 	}
1930291a2b48SSukumar Swaminathan 
1931fcf3ce44SJohn Forte 	if (found) {
1932fcf3ce44SJohn Forte 		/* Terminate at the last comma in string */
19338f23e9faSHans Rosenfeld 		vpd->prog_types[(strlen(vpd->prog_types) - 1)] = 0;
1934fcf3ce44SJohn Forte 	}
1935291a2b48SSukumar Swaminathan 
1936fcf3ce44SJohn Forte 	return;
1937fcf3ce44SJohn Forte 
193882527734SSukumar Swaminathan } /* emlxs_build_prog_types() */
1939fcf3ce44SJohn Forte 
1940fcf3ce44SJohn Forte 
1941fcf3ce44SJohn Forte extern uint32_t
1942fcf3ce44SJohn Forte emlxs_init_adapter_info(emlxs_hba_t *hba)
1943fcf3ce44SJohn Forte {
1944fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1945fcf3ce44SJohn Forte 	uint32_t pci_id;
1946fcf3ce44SJohn Forte 	uint32_t cache_line;
1947fcf3ce44SJohn Forte 	uint32_t channels;
1948*a3170057SPaul Winder 	uint16_t vendor_id;
1949fcf3ce44SJohn Forte 	uint16_t device_id;
1950fcf3ce44SJohn Forte 	uint16_t ssdid;
1951fcf3ce44SJohn Forte 	uint32_t i;
1952fcf3ce44SJohn Forte 	uint32_t found = 0;
195382527734SSukumar Swaminathan 	int32_t *prop;
195482527734SSukumar Swaminathan 	uint32_t num_prop;
1955fcf3ce44SJohn Forte 
1956fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
1957fcf3ce44SJohn Forte 		if (hba->pci_acc_handle == NULL) {
1958fcf3ce44SJohn Forte 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
1959fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
1960fcf3ce44SJohn Forte 
1961*a3170057SPaul Winder 			hba->model_info.vendor_id = 0;
1962fcf3ce44SJohn Forte 			hba->model_info.device_id = 0;
1963fcf3ce44SJohn Forte 
1964fcf3ce44SJohn Forte 			return (0);
1965fcf3ce44SJohn Forte 		}
1966291a2b48SSukumar Swaminathan 
1967fcf3ce44SJohn Forte 		/* Read the PCI device id */
1968291a2b48SSukumar Swaminathan 		pci_id =
1969291a2b48SSukumar Swaminathan 		    ddi_get32(hba->pci_acc_handle,
1970fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
1971*a3170057SPaul Winder 		vendor_id = (uint16_t)pci_id;
1972fcf3ce44SJohn Forte 		device_id = (uint16_t)(pci_id >> 16);
1973fcf3ce44SJohn Forte 
1974fcf3ce44SJohn Forte 		/* Find matching adapter model */
1975fcf3ce44SJohn Forte 		for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
1976*a3170057SPaul Winder 			if (emlxs_sbus_model[i].vendor_id == vendor_id &&
1977*a3170057SPaul Winder 			    emlxs_sbus_model[i].device_id == device_id) {
1978fcf3ce44SJohn Forte 				bcopy(&emlxs_sbus_model[i], &hba->model_info,
1979fcf3ce44SJohn Forte 				    sizeof (emlxs_model_t));
1980fcf3ce44SJohn Forte 				found = 1;
1981fcf3ce44SJohn Forte 				break;
1982fcf3ce44SJohn Forte 			}
1983fcf3ce44SJohn Forte 		}
1984fcf3ce44SJohn Forte 
1985fcf3ce44SJohn Forte 		/* If not found then use the unknown model */
1986fcf3ce44SJohn Forte 		if (!found) {
1987fcf3ce44SJohn Forte 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
1988fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
1989fcf3ce44SJohn Forte 
1990*a3170057SPaul Winder 			hba->model_info.vendor_id = vendor_id;
1991fcf3ce44SJohn Forte 			hba->model_info.device_id = device_id;
1992fcf3ce44SJohn Forte 
1993fcf3ce44SJohn Forte 			return (0);
1994fcf3ce44SJohn Forte 		}
1995fcf3ce44SJohn Forte 	} else {	/* PCI model */
1996291a2b48SSukumar Swaminathan 
1997fcf3ce44SJohn Forte 		if (hba->pci_acc_handle == NULL) {
1998fcf3ce44SJohn Forte 			bcopy(&emlxs_pci_model[0], &hba->model_info,
1999fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
2000fcf3ce44SJohn Forte 
2001*a3170057SPaul Winder 			hba->model_info.vendor_id = 0;
2002fcf3ce44SJohn Forte 			hba->model_info.device_id = 0;
2003fcf3ce44SJohn Forte 
2004fcf3ce44SJohn Forte 			return (0);
2005fcf3ce44SJohn Forte 		}
2006291a2b48SSukumar Swaminathan 
2007*a3170057SPaul Winder 		/* Read the PCI vendor and device id */
2008*a3170057SPaul Winder 		vendor_id =
2009*a3170057SPaul Winder 		    ddi_get16(hba->pci_acc_handle,
2010*a3170057SPaul Winder 		    (uint16_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
2011*a3170057SPaul Winder 
2012291a2b48SSukumar Swaminathan 		device_id =
2013291a2b48SSukumar Swaminathan 		    ddi_get16(hba->pci_acc_handle,
2014fcf3ce44SJohn Forte 		    (uint16_t *)(hba->pci_addr + PCI_DEVICE_ID_REGISTER));
2015fcf3ce44SJohn Forte 
2016fcf3ce44SJohn Forte 		/* Read the PCI Subsystem id */
2017291a2b48SSukumar Swaminathan 		ssdid =
2018291a2b48SSukumar Swaminathan 		    ddi_get16(hba->pci_acc_handle,
2019fcf3ce44SJohn Forte 		    (uint16_t *)(hba->pci_addr + PCI_SSDID_REGISTER));
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 		if (ssdid == 0 || ssdid == 0xffff) {
2022fcf3ce44SJohn Forte 			ssdid = device_id;
2023fcf3ce44SJohn Forte 		}
2024291a2b48SSukumar Swaminathan 
2025fcf3ce44SJohn Forte 		/* Read the Cache Line reg */
2026291a2b48SSukumar Swaminathan 		cache_line =
2027291a2b48SSukumar Swaminathan 		    ddi_get32(hba->pci_acc_handle,
2028fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + PCI_CACHE_LINE_REGISTER));
2029fcf3ce44SJohn Forte 
2030*a3170057SPaul Winder 		EMLXS_MSGF(EMLXS_CONTEXT,
2031*a3170057SPaul Winder 		    &emlxs_init_debug_msg, "Device IDs: %x/%x/%x/%x",
2032*a3170057SPaul Winder 		    vendor_id, device_id, ssdid, cache_line);
2033*a3170057SPaul Winder 
2034fcf3ce44SJohn Forte 		/* Check for the multifunction bit being set */
2035fcf3ce44SJohn Forte 		if ((cache_line & 0x00ff0000) == 0x00800000) {
20368f23e9faSHans Rosenfeld 			channels = EMLXS_MULTI_CHANNEL;
2037fcf3ce44SJohn Forte 		} else {
20388f23e9faSHans Rosenfeld 			channels = EMLXS_SINGLE_CHANNEL;
2039fcf3ce44SJohn Forte 		}
2040fcf3ce44SJohn Forte 
2041fcf3ce44SJohn Forte 		/* If device ids are unique, then use them for search */
2042fcf3ce44SJohn Forte 		if (device_id != ssdid) {
20438f23e9faSHans Rosenfeld 			/*
20448f23e9faSHans Rosenfeld 			 * Find matching adapter model using
2045*a3170057SPaul Winder 			 * vendor_id, device_id, ssdid, and channels
20468f23e9faSHans Rosenfeld 			 */
20478f23e9faSHans Rosenfeld 			for (i = 1; i < emlxs_pci_model_count; i++) {
2048*a3170057SPaul Winder 				if (emlxs_pci_model[i].vendor_id == vendor_id &&
2049*a3170057SPaul Winder 				    emlxs_pci_model[i].device_id == device_id &&
20508f23e9faSHans Rosenfeld 				    emlxs_pci_model[i].ssdid == ssdid &&
20518f23e9faSHans Rosenfeld 				    emlxs_pci_model[i].channels ==
20528f23e9faSHans Rosenfeld 				    channels) {
20538f23e9faSHans Rosenfeld 					bcopy(&emlxs_pci_model[i],
20548f23e9faSHans Rosenfeld 					    &hba->model_info,
20558f23e9faSHans Rosenfeld 					    sizeof (emlxs_model_t));
20568f23e9faSHans Rosenfeld 					found = 1;
20578f23e9faSHans Rosenfeld 					break;
2058fcf3ce44SJohn Forte 				}
2059fcf3ce44SJohn Forte 			}
2060fcf3ce44SJohn Forte 		}
2061291a2b48SSukumar Swaminathan 
2062fcf3ce44SJohn Forte 		/* If adapter not found, try again */
2063fcf3ce44SJohn Forte 		if (!found) {
20648f23e9faSHans Rosenfeld 			/*
20658f23e9faSHans Rosenfeld 			 * Find matching adapter model using
2066*a3170057SPaul Winder 			 * vendor_id, device_id and channels
20678f23e9faSHans Rosenfeld 			 */
206882527734SSukumar Swaminathan 			for (i = 1; i < emlxs_pci_model_count; i++) {
2069*a3170057SPaul Winder 				if (emlxs_pci_model[i].vendor_id == vendor_id &&
2070*a3170057SPaul Winder 				    emlxs_pci_model[i].device_id == device_id &&
2071fcf3ce44SJohn Forte 				    emlxs_pci_model[i].channels == channels) {
2072fcf3ce44SJohn Forte 					bcopy(&emlxs_pci_model[i],
2073fcf3ce44SJohn Forte 					    &hba->model_info,
2074fcf3ce44SJohn Forte 					    sizeof (emlxs_model_t));
2075fcf3ce44SJohn Forte 					found = 1;
2076fcf3ce44SJohn Forte 					break;
2077fcf3ce44SJohn Forte 				}
2078fcf3ce44SJohn Forte 			}
2079fcf3ce44SJohn Forte 		}
2080291a2b48SSukumar Swaminathan 
2081fcf3ce44SJohn Forte 		/* If adapter not found, try one last time */
2082fcf3ce44SJohn Forte 		if (!found) {
20838f23e9faSHans Rosenfeld 			/*
20848f23e9faSHans Rosenfeld 			 * Find matching adapter model using
2085*a3170057SPaul Winder 			 * vendor_id and device_id only
20868f23e9faSHans Rosenfeld 			 */
208782527734SSukumar Swaminathan 			for (i = 1; i < emlxs_pci_model_count; i++) {
2088*a3170057SPaul Winder 				if (emlxs_pci_model[i].vendor_id == vendor_id &&
2089*a3170057SPaul Winder 				    emlxs_pci_model[i].device_id == device_id) {
2090fcf3ce44SJohn Forte 					bcopy(&emlxs_pci_model[i],
2091fcf3ce44SJohn Forte 					    &hba->model_info,
2092fcf3ce44SJohn Forte 					    sizeof (emlxs_model_t));
2093fcf3ce44SJohn Forte 					found = 1;
2094fcf3ce44SJohn Forte 					break;
2095fcf3ce44SJohn Forte 				}
2096fcf3ce44SJohn Forte 			}
2097fcf3ce44SJohn Forte 		}
2098291a2b48SSukumar Swaminathan 
2099fcf3ce44SJohn Forte 		/* If not found, set adapter to unknown */
2100fcf3ce44SJohn Forte 		if (!found) {
2101fcf3ce44SJohn Forte 			bcopy(&emlxs_pci_model[0], &hba->model_info,
2102fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
2103fcf3ce44SJohn Forte 
2104*a3170057SPaul Winder 			hba->model_info.vendor_id = vendor_id;
2105fcf3ce44SJohn Forte 			hba->model_info.device_id = device_id;
2106fcf3ce44SJohn Forte 			hba->model_info.ssdid = ssdid;
2107fcf3ce44SJohn Forte 
2108fcf3ce44SJohn Forte 			return (0);
2109fcf3ce44SJohn Forte 		}
2110fcf3ce44SJohn Forte 
2111fcf3ce44SJohn Forte #ifndef SATURN_MSI_SUPPORT
2112fcf3ce44SJohn Forte 		/*
2113291a2b48SSukumar Swaminathan 		 * This will disable MSI support for Saturn adapter's
2114291a2b48SSukumar Swaminathan 		 * due to a PCI bus issue
2115fcf3ce44SJohn Forte 		 */
2116fcf3ce44SJohn Forte 		if (hba->model_info.chip == EMLXS_SATURN_CHIP) {
2117fcf3ce44SJohn Forte 			hba->model_info.flags &=
2118fcf3ce44SJohn Forte 			    ~(EMLXS_MSI_SUPPORTED | EMLXS_MSIX_SUPPORTED);
2119fcf3ce44SJohn Forte 		}
2120291a2b48SSukumar Swaminathan #endif /* !SATURN_MSI_SUPPORT */
2121fcf3ce44SJohn Forte 
2122a9800bebSGarrett D'Amore 		/* Scan the PCI capabilities */
2123a9800bebSGarrett D'Amore 		emlxs_pci_cap_offsets(hba);
2124fcf3ce44SJohn Forte 
2125fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
2126fcf3ce44SJohn Forte 		/* Verify MSI support */
2127a9800bebSGarrett D'Amore 		if ((hba->model_info.flags & EMLXS_MSI_SUPPORTED) &&
2128a9800bebSGarrett D'Amore 		    !hba->pci_cap_offset[PCI_CAP_ID_MSI]) {
2129a9800bebSGarrett D'Amore 			hba->model_info.flags &= ~EMLXS_MSI_SUPPORTED;
2130fcf3ce44SJohn Forte 		}
2131291a2b48SSukumar Swaminathan 
2132fcf3ce44SJohn Forte 		/* Verify MSI-X support */
2133a9800bebSGarrett D'Amore 		if ((hba->model_info.flags & EMLXS_MSIX_SUPPORTED) &&
2134a9800bebSGarrett D'Amore 		    !hba->pci_cap_offset[PCI_CAP_ID_MSI_X]) {
2135a9800bebSGarrett D'Amore 			hba->model_info.flags &= ~EMLXS_MSIX_SUPPORTED;
2136fcf3ce44SJohn Forte 		}
2137291a2b48SSukumar Swaminathan #endif /* MSI_SUPPORT */
21388f23e9faSHans Rosenfeld 
21398f23e9faSHans Rosenfeld 		/* Set the sli_intf value */
21408f23e9faSHans Rosenfeld 		if (hba->pci_cap_offset[PCI_CAP_ID_VS]) {
21418f23e9faSHans Rosenfeld 			/* Save the SLI_INTF register, this contains */
21428f23e9faSHans Rosenfeld 			/* information about the BAR register layout */
21438f23e9faSHans Rosenfeld 			/* and other HBA information. */
21448f23e9faSHans Rosenfeld 			hba->sli_intf =
21458f23e9faSHans Rosenfeld 			    ddi_get32(hba->pci_acc_handle,
21468f23e9faSHans Rosenfeld 			    (uint32_t *)(hba->pci_addr +
21478f23e9faSHans Rosenfeld 			    hba->pci_cap_offset[PCI_CAP_ID_VS] +
21488f23e9faSHans Rosenfeld 			    PCI_VS_SLI_INTF_OFFSET));
21498f23e9faSHans Rosenfeld 
21508f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT,
21518f23e9faSHans Rosenfeld 			    &emlxs_init_debug_msg, "PCI_CAP_ID_VS: "
21528f23e9faSHans Rosenfeld 			    "SLI_INTF:%08x",
21538f23e9faSHans Rosenfeld 			    hba->sli_intf);
21548f23e9faSHans Rosenfeld 
21558f23e9faSHans Rosenfeld 			/* Check validity */
21568f23e9faSHans Rosenfeld 			if ((hba->sli_intf & SLI_INTF_VALID_MASK) !=
21578f23e9faSHans Rosenfeld 			    SLI_INTF_VALID) {
21588f23e9faSHans Rosenfeld 				hba->sli_intf = 0;
21598f23e9faSHans Rosenfeld 			}
21608f23e9faSHans Rosenfeld 		}
2161291a2b48SSukumar Swaminathan 	}
2162fcf3ce44SJohn Forte 
216382527734SSukumar Swaminathan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba->dip, 0,
216482527734SSukumar Swaminathan 	    "reg", &prop, &num_prop) == DDI_PROP_SUCCESS) {
216582527734SSukumar Swaminathan 		/* Parse the property for PCI function, device and bus no. */
216682527734SSukumar Swaminathan 		hba->pci_function_number =
216782527734SSukumar Swaminathan 		    (uint8_t)((prop[0] & 0x00000700) >> 8);
21688f23e9faSHans Rosenfeld 		hba->pci_device_number =
21698f23e9faSHans Rosenfeld 		    (uint8_t)((prop[0] & 0x0000f800) >> 11);
217082527734SSukumar Swaminathan 		hba->pci_bus_number = (uint8_t)((prop[0] & 0x00ff0000) >> 16);
217182527734SSukumar Swaminathan 		ddi_prop_free((void *)prop);
217282527734SSukumar Swaminathan 	}
217382527734SSukumar Swaminathan 
21748f23e9faSHans Rosenfeld 	switch (hba->sli_intf & SLI_INTF_SLI_REV_MASK) {
21758f23e9faSHans Rosenfeld 	case SLI_INTF_SLI_REV_NONE: /* Legacy support */
21768f23e9faSHans Rosenfeld 		if (hba->model_info.sli_mask & EMLXS_SLI4_MASK) {
21778f23e9faSHans Rosenfeld 			hba->sli_api = emlxs_sli4_api;
21788f23e9faSHans Rosenfeld 		} else {
21798f23e9faSHans Rosenfeld 			hba->sli_api = emlxs_sli3_api;
21808f23e9faSHans Rosenfeld 		}
21818f23e9faSHans Rosenfeld 		break;
21828f23e9faSHans Rosenfeld 
21838f23e9faSHans Rosenfeld 	case SLI_INTF_SLI_REV_3:
21848f23e9faSHans Rosenfeld 		if (!(hba->model_info.sli_mask & EMLXS_SLI3_MASK)) {
21858f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT,
21868f23e9faSHans Rosenfeld 			    &emlxs_init_failed_msg,
21878f23e9faSHans Rosenfeld 			    "Adapter does not support SLI3 interface. "
21888f23e9faSHans Rosenfeld 			    "sli_intf=%08x sli_mask=%08x",
21898f23e9faSHans Rosenfeld 			    hba->sli_intf, hba->model_info.sli_mask);
21908f23e9faSHans Rosenfeld 			return (0);
21918f23e9faSHans Rosenfeld 		}
219282527734SSukumar Swaminathan 		hba->sli_api = emlxs_sli3_api;
21938f23e9faSHans Rosenfeld 		break;
21948f23e9faSHans Rosenfeld 
21958f23e9faSHans Rosenfeld 	case SLI_INTF_SLI_REV_4:
21968f23e9faSHans Rosenfeld 		if (!(hba->model_info.sli_mask & EMLXS_SLI4_MASK)) {
21978f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT,
21988f23e9faSHans Rosenfeld 			    &emlxs_init_failed_msg,
21998f23e9faSHans Rosenfeld 			    "Adapter does not support SLI4 interface. "
22008f23e9faSHans Rosenfeld 			    "sli_intf=%08x sli_mask=%08x",
22018f23e9faSHans Rosenfeld 			    hba->sli_intf, hba->model_info.sli_mask);
22028f23e9faSHans Rosenfeld 			return (0);
22038f23e9faSHans Rosenfeld 		}
22048f23e9faSHans Rosenfeld 		hba->sli_api = emlxs_sli4_api;
22058f23e9faSHans Rosenfeld 		break;
22068f23e9faSHans Rosenfeld 
22078f23e9faSHans Rosenfeld 	default:
22088f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT,
22098f23e9faSHans Rosenfeld 		    &emlxs_init_failed_msg,
22108f23e9faSHans Rosenfeld 		    "Invalid SLI interface specified. "
22118f23e9faSHans Rosenfeld 		    "sli_intf=%08x sli_mask=%08x",
22128f23e9faSHans Rosenfeld 		    hba->sli_intf, hba->model_info.sli_mask);
22138f23e9faSHans Rosenfeld 		return (0);
221482527734SSukumar Swaminathan 	}
221582527734SSukumar Swaminathan 
22164baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
22174baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
22184baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
22194baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
22204baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
22214baa2c25SSukumar Swaminathan 		return (0);
22224baa2c25SSukumar Swaminathan 	}
22234baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
22244baa2c25SSukumar Swaminathan 
2225fcf3ce44SJohn Forte 	return (1);
2226fcf3ce44SJohn Forte 
222782527734SSukumar Swaminathan } /* emlxs_init_adapter_info()  */
2228fcf3ce44SJohn Forte 
2229fcf3ce44SJohn Forte 
2230291a2b48SSukumar Swaminathan /* ARGSUSED */
2231291a2b48SSukumar Swaminathan static void
223282527734SSukumar Swaminathan emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2233fcf3ce44SJohn Forte {
2234291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
2235291a2b48SSukumar Swaminathan 	IOCB *iocb;
2236291a2b48SSukumar Swaminathan 	uint32_t *w;
2237291a2b48SSukumar Swaminathan 	int i, j;
2238fcf3ce44SJohn Forte 
2239291a2b48SSukumar Swaminathan 	iocb = &iocbq->iocb;
2240fcf3ce44SJohn Forte 
224182527734SSukumar Swaminathan 	if (iocb->ULPSTATUS != 0) {
2242291a2b48SSukumar Swaminathan 		return;
2243fcf3ce44SJohn Forte 	}
2244fcf3ce44SJohn Forte 
2245291a2b48SSukumar Swaminathan 	switch (iocb->un.astat.EventCode) {
2246291a2b48SSukumar Swaminathan 	case 0x0100:	/* Temp Warning */
2247291a2b48SSukumar Swaminathan 
2248291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_warning_msg,
2249291a2b48SSukumar Swaminathan 		    "Adapter is very hot (%d �C). Take corrective action.",
225082527734SSukumar Swaminathan 		    iocb->ULPCONTEXT);
225182527734SSukumar Swaminathan 
225282527734SSukumar Swaminathan 		hba->temperature = iocb->ULPCONTEXT;
225382527734SSukumar Swaminathan 		emlxs_log_temp_event(port, 0x02, iocb->ULPCONTEXT);
2254fcf3ce44SJohn Forte 
2255fcf3ce44SJohn Forte 
2256291a2b48SSukumar Swaminathan 		break;
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte 
2259291a2b48SSukumar Swaminathan 	case 0x0101:	/* Temp Safe */
2260fcf3ce44SJohn Forte 
2261291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_msg,
2262291a2b48SSukumar Swaminathan 		    "Adapter temperature now safe (%d �C).",
226382527734SSukumar Swaminathan 		    iocb->ULPCONTEXT);
2264fcf3ce44SJohn Forte 
226582527734SSukumar Swaminathan 		hba->temperature = iocb->ULPCONTEXT;
226682527734SSukumar Swaminathan 		emlxs_log_temp_event(port, 0x03, iocb->ULPCONTEXT);
2267fcf3ce44SJohn Forte 
2268291a2b48SSukumar Swaminathan 		break;
2269fcf3ce44SJohn Forte 
2270291a2b48SSukumar Swaminathan 	default:
2271fcf3ce44SJohn Forte 
2272291a2b48SSukumar Swaminathan 		w = (uint32_t *)iocb;
2273291a2b48SSukumar Swaminathan 		for (i = 0, j = 0; i < 8; i++, j += 2) {
2274291a2b48SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_async_msg,
2275291a2b48SSukumar Swaminathan 			    "(Word[%d]=%x Word[%d]=%x)", j, w[j], j + 1,
2276291a2b48SSukumar Swaminathan 			    w[j + 1]);
2277291a2b48SSukumar Swaminathan 		}
2278fcf3ce44SJohn Forte 
2279291a2b48SSukumar Swaminathan 		emlxs_log_async_event(port, iocb);
2280fcf3ce44SJohn Forte 	}
2281fcf3ce44SJohn Forte 
2282fcf3ce44SJohn Forte 	return;
2283fcf3ce44SJohn Forte 
228482527734SSukumar Swaminathan } /* emlxs_handle_async_event() */
2285fcf3ce44SJohn Forte 
2286fcf3ce44SJohn Forte 
2287bb63f56eSSukumar Swaminathan /* ARGSUSED */
2288291a2b48SSukumar Swaminathan extern void
2289bb63f56eSSukumar Swaminathan emlxs_reset_link_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2290fcf3ce44SJohn Forte {
2291291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
2292fcf3ce44SJohn Forte 
2293291a2b48SSukumar Swaminathan 	/* Attempt a link reset to recover */
2294291a2b48SSukumar Swaminathan 	(void) emlxs_reset(port, FC_FCA_LINK_RESET);
2295fcf3ce44SJohn Forte 
2296bb63f56eSSukumar Swaminathan 	return;
2297fcf3ce44SJohn Forte 
229882527734SSukumar Swaminathan } /* emlxs_reset_link_thread() */
2299fcf3ce44SJohn Forte 
2300fcf3ce44SJohn Forte 
2301bb63f56eSSukumar Swaminathan /* ARGSUSED */
2302fcf3ce44SJohn Forte extern void
2303bb63f56eSSukumar Swaminathan emlxs_restart_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2304fcf3ce44SJohn Forte {
2305fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2306fcf3ce44SJohn Forte 
2307fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Restarting...");
2308fcf3ce44SJohn Forte 
2309fcf3ce44SJohn Forte 	/* Attempt a full hardware reset to recover */
2310fcf3ce44SJohn Forte 	if (emlxs_reset(port, FC_FCA_RESET) != FC_SUCCESS) {
231182527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE(hba, FC_ERROR);
2312fcf3ce44SJohn Forte 
231382527734SSukumar Swaminathan 		emlxs_shutdown_thread(hba, arg1, arg2);
2314fcf3ce44SJohn Forte 	}
2315fcf3ce44SJohn Forte 
2316bb63f56eSSukumar Swaminathan 	return;
2317291a2b48SSukumar Swaminathan 
231882527734SSukumar Swaminathan } /* emlxs_restart_thread() */
2319fcf3ce44SJohn Forte 
2320fcf3ce44SJohn Forte 
2321bb63f56eSSukumar Swaminathan /* ARGSUSED */
2322fcf3ce44SJohn Forte extern void
2323bb63f56eSSukumar Swaminathan emlxs_shutdown_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2324fcf3ce44SJohn Forte {
2325fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2326fcf3ce44SJohn Forte 
2327fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
2328fcf3ce44SJohn Forte 	if (hba->flag & FC_SHUTDOWN) {
2329fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
2330bb63f56eSSukumar Swaminathan 		return;
2331fcf3ce44SJohn Forte 	}
2332fcf3ce44SJohn Forte 	hba->flag |= FC_SHUTDOWN;
2333fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
2334fcf3ce44SJohn Forte 
2335291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
2336291a2b48SSukumar Swaminathan 	    "Shutting down...");
2337fcf3ce44SJohn Forte 
2338fcf3ce44SJohn Forte 	/* Take adapter offline and leave it there */
23398f23e9faSHans Rosenfeld 	(void) emlxs_offline(hba, 0);
2340fcf3ce44SJohn Forte 
234182527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
234282527734SSukumar Swaminathan 		/*
234382527734SSukumar Swaminathan 		 * Dump is not defined for SLI4, so just
234482527734SSukumar Swaminathan 		 * reset the HBA for now.
234582527734SSukumar Swaminathan 		 */
234682527734SSukumar Swaminathan 		EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
234782527734SSukumar Swaminathan 
234882527734SSukumar Swaminathan 	} else {
234982527734SSukumar Swaminathan 		if (hba->flag & FC_OVERTEMP_EVENT) {
235082527734SSukumar Swaminathan 			emlxs_log_temp_event(port, 0x01,
235182527734SSukumar Swaminathan 			    hba->temperature);
235282527734SSukumar Swaminathan 		} else {
235382527734SSukumar Swaminathan 			emlxs_log_dump_event(port, NULL, 0);
235482527734SSukumar Swaminathan 		}
235582527734SSukumar Swaminathan 	}
2356fcf3ce44SJohn Forte 
2357fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_shutdown_msg, "Reboot required.");
2358fcf3ce44SJohn Forte 
2359bb63f56eSSukumar Swaminathan 	return;
2360fcf3ce44SJohn Forte 
236182527734SSukumar Swaminathan } /* emlxs_shutdown_thread() */
2362fcf3ce44SJohn Forte 
2363fcf3ce44SJohn Forte 
2364fcf3ce44SJohn Forte /* ARGSUSED */
2365fcf3ce44SJohn Forte extern void
236682527734SSukumar Swaminathan emlxs_proc_channel(emlxs_hba_t *hba, CHANNEL *cp, void *arg2)
2367fcf3ce44SJohn Forte {
2368fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2369fcf3ce44SJohn Forte 	IOCBQ *rsp_head;
2370fcf3ce44SJohn Forte 
2371fcf3ce44SJohn Forte 	/*
2372291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
23738f23e9faSHans Rosenfeld 	 * "proc_channel: channel=%d", cp->channelno);
2374fcf3ce44SJohn Forte 	 */
2375fcf3ce44SJohn Forte 
237682527734SSukumar Swaminathan 	mutex_enter(&cp->rsp_lock);
2377fcf3ce44SJohn Forte 
237882527734SSukumar Swaminathan 	while ((rsp_head = cp->rsp_head) != NULL) {
237982527734SSukumar Swaminathan 		cp->rsp_head = NULL;
238082527734SSukumar Swaminathan 		cp->rsp_tail = NULL;
2381fcf3ce44SJohn Forte 
238282527734SSukumar Swaminathan 		mutex_exit(&cp->rsp_lock);
2383fcf3ce44SJohn Forte 
2384fcf3ce44SJohn Forte 		while ((iocbq = rsp_head) != NULL) {
2385fcf3ce44SJohn Forte 			rsp_head = (IOCBQ *) iocbq->next;
2386fcf3ce44SJohn Forte 
238782527734SSukumar Swaminathan 			emlxs_proc_channel_event(hba, cp, iocbq);
2388fcf3ce44SJohn Forte 		}
2389fcf3ce44SJohn Forte 
239082527734SSukumar Swaminathan 		mutex_enter(&cp->rsp_lock);
2391fcf3ce44SJohn Forte 	}
2392fcf3ce44SJohn Forte 
239382527734SSukumar Swaminathan 	mutex_exit(&cp->rsp_lock);
2394fcf3ce44SJohn Forte 
239582527734SSukumar Swaminathan 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0);
2396fcf3ce44SJohn Forte 
2397fcf3ce44SJohn Forte 	return;
2398fcf3ce44SJohn Forte 
239982527734SSukumar Swaminathan } /* emlxs_proc_channel() */
2400fcf3ce44SJohn Forte 
2401fcf3ce44SJohn Forte 
2402fcf3ce44SJohn Forte /*
2403291a2b48SSukumar Swaminathan  * Called from SLI ring event routines to process a rsp ring IOCB.
2404fcf3ce44SJohn Forte  */
2405291a2b48SSukumar Swaminathan void
240682527734SSukumar Swaminathan emlxs_proc_channel_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2407fcf3ce44SJohn Forte {
2408fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2409fcf3ce44SJohn Forte 	char buffer[MAX_MSG_DATA + 1];
2410fcf3ce44SJohn Forte 	IOCB *iocb;
241182527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
24128f23e9faSHans Rosenfeld 	fc_packet_t *pkt;
2413fcf3ce44SJohn Forte 
2414fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
2415fcf3ce44SJohn Forte 
241682527734SSukumar Swaminathan #ifdef DEBUG_CMPL_IOCB
2417a9800bebSGarrett D'Amore 	emlxs_data_dump(port, "CMPL_IOCB", (uint32_t *)iocb, 8, 0);
241882527734SSukumar Swaminathan #endif
241982527734SSukumar Swaminathan 
242082527734SSukumar Swaminathan 	sbp = (emlxs_buf_t *)iocbq->sbp;
242182527734SSukumar Swaminathan 	if (sbp) {
242282527734SSukumar Swaminathan 		if (!(sbp->pkt_flags & PACKET_VALID) ||
242382527734SSukumar Swaminathan 		    (sbp->pkt_flags & (PACKET_ULP_OWNED |
242482527734SSukumar Swaminathan 		    PACKET_IN_COMPLETION))) {
242582527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_stale_msg,
242682527734SSukumar Swaminathan 			    "Duplicate: iocb=%p cmd=%x status=%x "
24278f23e9faSHans Rosenfeld 			    "error=%x iotag=%d context=%x info=%x",
242882527734SSukumar Swaminathan 			    iocbq, (uint8_t)iocbq->iocb.ULPCOMMAND,
242982527734SSukumar Swaminathan 			    iocbq->iocb.ULPSTATUS,
243082527734SSukumar Swaminathan 			    (uint8_t)iocbq->iocb.un.grsp.perr.statLocalError,
243182527734SSukumar Swaminathan 			    (uint16_t)iocbq->iocb.ULPIOTAG,
243282527734SSukumar Swaminathan 			    (uint16_t)iocbq->iocb.ULPCONTEXT,
243382527734SSukumar Swaminathan 			    (uint8_t)iocbq->iocb.ULPRSVDBYTE);
243482527734SSukumar Swaminathan 
243582527734SSukumar Swaminathan 			/* Drop this IO immediately */
243682527734SSukumar Swaminathan 			return;
243782527734SSukumar Swaminathan 		}
243882527734SSukumar Swaminathan 
243982527734SSukumar Swaminathan 		if (sbp->pkt_flags & PACKET_IN_TIMEOUT) {
244082527734SSukumar Swaminathan 			/*
244182527734SSukumar Swaminathan 			 * If the packet is tagged for timeout then set the
244282527734SSukumar Swaminathan 			 * return codes appropriately
244382527734SSukumar Swaminathan 			 */
244482527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
244582527734SSukumar Swaminathan 			iocb->un.grsp.perr.statLocalError = IOERR_ABORT_TIMEOUT;
244682527734SSukumar Swaminathan 		} else if (sbp->pkt_flags &
244782527734SSukumar Swaminathan 		    (PACKET_IN_FLUSH | PACKET_IN_ABORT)) {
244882527734SSukumar Swaminathan 			/*
244982527734SSukumar Swaminathan 			 * If the packet is tagged for abort then set the
245082527734SSukumar Swaminathan 			 * return codes appropriately
245182527734SSukumar Swaminathan 			 */
245282527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
245382527734SSukumar Swaminathan 			iocb->un.grsp.perr.statLocalError =
245482527734SSukumar Swaminathan 			    IOERR_ABORT_REQUESTED;
245582527734SSukumar Swaminathan 		}
245682527734SSukumar Swaminathan 	}
245782527734SSukumar Swaminathan 
2458fcf3ce44SJohn Forte 	/* Check for IOCB local error */
245982527734SSukumar Swaminathan 	if (iocb->ULPSTATUS == IOSTAT_LOCAL_REJECT) {
2460fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_event_msg,
2461291a2b48SSukumar Swaminathan 		    "Local reject. ringno=%d iocb=%p cmd=%x "
24628f23e9faSHans Rosenfeld 		    "iotag=%d context=%x info=%x error=%x",
246382527734SSukumar Swaminathan 		    cp->channelno, iocb, (uint8_t)iocb->ULPCOMMAND,
246482527734SSukumar Swaminathan 		    (uint16_t)iocb->ULPIOTAG, (uint16_t)iocb->ULPCONTEXT,
246582527734SSukumar Swaminathan 		    (uint8_t)iocb->ULPRSVDBYTE,
2466fcf3ce44SJohn Forte 		    (uint8_t)iocb->un.grsp.perr.statLocalError);
2467fcf3ce44SJohn Forte 	}
2468291a2b48SSukumar Swaminathan 
246982527734SSukumar Swaminathan 	switch (iocb->ULPCOMMAND) {
2470fcf3ce44SJohn Forte 		/* RING 0 FCP commands */
2471fcf3ce44SJohn Forte 	case CMD_FCP_ICMND_CR:
2472fcf3ce44SJohn Forte 	case CMD_FCP_ICMND_CX:
2473fcf3ce44SJohn Forte 	case CMD_FCP_IREAD_CR:
2474fcf3ce44SJohn Forte 	case CMD_FCP_IREAD_CX:
2475fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE_CR:
2476fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE_CX:
2477fcf3ce44SJohn Forte 	case CMD_FCP_ICMND64_CR:
2478fcf3ce44SJohn Forte 	case CMD_FCP_ICMND64_CX:
2479fcf3ce44SJohn Forte 	case CMD_FCP_IREAD64_CR:
2480fcf3ce44SJohn Forte 	case CMD_FCP_IREAD64_CX:
2481fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE64_CR:
2482fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE64_CX:
248382527734SSukumar Swaminathan 		emlxs_handle_fcp_event(hba, cp, iocbq);
2484fcf3ce44SJohn Forte 		break;
2485fcf3ce44SJohn Forte 
2486fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
2487291a2b48SSukumar Swaminathan 	case CMD_FCP_TSEND_CX:		/* FCP_TARGET IOCB command */
2488fcf3ce44SJohn Forte 	case CMD_FCP_TSEND64_CX:	/* FCP_TARGET IOCB command */
2489fcf3ce44SJohn Forte 	case CMD_FCP_TRECEIVE_CX:	/* FCP_TARGET IOCB command */
2490fcf3ce44SJohn Forte 	case CMD_FCP_TRECEIVE64_CX:	/* FCP_TARGET IOCB command */
2491291a2b48SSukumar Swaminathan 	case CMD_FCP_TRSP_CX:		/* FCP_TARGET IOCB command */
2492291a2b48SSukumar Swaminathan 	case CMD_FCP_TRSP64_CX:		/* FCP_TARGET IOCB command */
24938f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
24948f23e9faSHans Rosenfeld 			(void) emlxs_fct_handle_fcp_event(hba, cp, iocbq);
24958f23e9faSHans Rosenfeld 		}
2496fcf3ce44SJohn Forte 		break;
2497291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2498fcf3ce44SJohn Forte 
2499fcf3ce44SJohn Forte 		/* RING 1 IP commands */
2500fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST_CN:
2501fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST_CX:
2502fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST64_CN:
2503fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST64_CX:
250482527734SSukumar Swaminathan 		(void) emlxs_ip_handle_event(hba, cp, iocbq);
2505fcf3ce44SJohn Forte 		break;
2506fcf3ce44SJohn Forte 
2507fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE_CX:
2508fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE_CR:
2509fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE64_CX:
2510fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE64_CR:
2511fcf3ce44SJohn Forte 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2512fcf3ce44SJohn Forte 		case FC_TYPE_IS8802_SNAP:
251382527734SSukumar Swaminathan 			(void) emlxs_ip_handle_event(hba, cp, iocbq);
2514fcf3ce44SJohn Forte 			break;
2515fcf3ce44SJohn Forte 
2516fcf3ce44SJohn Forte 		case FC_TYPE_FC_SERVICES:
251782527734SSukumar Swaminathan 			(void) emlxs_ct_handle_event(hba, cp, iocbq);
2518fcf3ce44SJohn Forte 			break;
2519fcf3ce44SJohn Forte 
2520fcf3ce44SJohn Forte 		default:
2521fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
25228f23e9faSHans Rosenfeld 			    "cmd=%x type=%x status=%x iotag=%d context=%x ",
252382527734SSukumar Swaminathan 			    iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
252482527734SSukumar Swaminathan 			    iocb->ULPSTATUS, iocb->ULPIOTAG,
252582527734SSukumar Swaminathan 			    iocb->ULPCONTEXT);
2526fcf3ce44SJohn Forte 		}
2527fcf3ce44SJohn Forte 		break;
2528fcf3ce44SJohn Forte 
2529fcf3ce44SJohn Forte 	case CMD_RCV_SEQUENCE_CX:
2530fcf3ce44SJohn Forte 	case CMD_RCV_SEQUENCE64_CX:
2531fcf3ce44SJohn Forte 	case CMD_RCV_SEQ64_CX:
2532fcf3ce44SJohn Forte 	case CMD_RCV_ELS_REQ_CX:	/* Unsolicited ELS frame  */
2533fcf3ce44SJohn Forte 	case CMD_RCV_ELS_REQ64_CX:	/* Unsolicited ELS frame  */
2534291a2b48SSukumar Swaminathan 	case CMD_RCV_ELS64_CX:		/* Unsolicited ELS frame  */
253582527734SSukumar Swaminathan 		if (hba->sli_mode <= EMLXS_HBA_SLI3_MODE) {
253682527734SSukumar Swaminathan 			(void) emlxs_handle_rcv_seq(hba, cp, iocbq);
253782527734SSukumar Swaminathan 		}
2538fcf3ce44SJohn Forte 		break;
2539fcf3ce44SJohn Forte 
2540fcf3ce44SJohn Forte 	case CMD_RCV_SEQ_LIST64_CX:
254182527734SSukumar Swaminathan 		(void) emlxs_ip_handle_rcv_seq_list(hba, cp, iocbq);
2542fcf3ce44SJohn Forte 		break;
2543fcf3ce44SJohn Forte 
2544fcf3ce44SJohn Forte 	case CMD_CREATE_XRI_CR:
2545fcf3ce44SJohn Forte 	case CMD_CREATE_XRI_CX:
254682527734SSukumar Swaminathan 		(void) emlxs_handle_create_xri(hba, cp, iocbq);
2547fcf3ce44SJohn Forte 		break;
2548fcf3ce44SJohn Forte 
2549fcf3ce44SJohn Forte 		/* RING 2 ELS commands */
2550fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST_CR:
2551fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST_CX:
2552fcf3ce44SJohn Forte 	case CMD_XMIT_ELS_RSP_CX:
2553fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST64_CR:
2554fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST64_CX:
2555fcf3ce44SJohn Forte 	case CMD_XMIT_ELS_RSP64_CX:
255682527734SSukumar Swaminathan 		(void) emlxs_els_handle_event(hba, cp, iocbq);
2557fcf3ce44SJohn Forte 		break;
2558fcf3ce44SJohn Forte 
2559fcf3ce44SJohn Forte 		/* RING 3 CT commands */
2560fcf3ce44SJohn Forte 	case CMD_GEN_REQUEST64_CR:
2561fcf3ce44SJohn Forte 	case CMD_GEN_REQUEST64_CX:
2562fcf3ce44SJohn Forte 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2563fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
2564fcf3ce44SJohn Forte 		case EMLXS_MENLO_TYPE:
256582527734SSukumar Swaminathan 			(void) emlxs_menlo_handle_event(hba, cp, iocbq);
2566fcf3ce44SJohn Forte 			break;
2567291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
2568fcf3ce44SJohn Forte 
2569fcf3ce44SJohn Forte 		case FC_TYPE_FC_SERVICES:
257082527734SSukumar Swaminathan 			(void) emlxs_ct_handle_event(hba, cp, iocbq);
2571fcf3ce44SJohn Forte 			break;
2572fcf3ce44SJohn Forte 
2573fcf3ce44SJohn Forte 		default:
2574fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
25758f23e9faSHans Rosenfeld 			    "cmd=%x type=%x status=%x iotag=%d context=%x ",
257682527734SSukumar Swaminathan 			    iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
257782527734SSukumar Swaminathan 			    iocb->ULPSTATUS, iocb->ULPIOTAG,
257882527734SSukumar Swaminathan 			    iocb->ULPCONTEXT);
2579fcf3ce44SJohn Forte 		}
2580fcf3ce44SJohn Forte 		break;
2581fcf3ce44SJohn Forte 
2582fcf3ce44SJohn Forte 	case CMD_ABORT_XRI_CN:	/* Abort fcp command */
2583fcf3ce44SJohn Forte 
2584fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
25858f23e9faSHans Rosenfeld 		    "ABORT_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2586fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
258782527734SSukumar Swaminathan 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2588291a2b48SSukumar Swaminathan 		    iocb->un.acxri.parm);
2589fcf3ce44SJohn Forte 
2590291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
25918f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
259282527734SSukumar Swaminathan 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2593291a2b48SSukumar Swaminathan 		}
2594291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2595fcf3ce44SJohn Forte 		break;
2596fcf3ce44SJohn Forte 
2597fcf3ce44SJohn Forte 	case CMD_ABORT_XRI_CX:	/* Abort command */
2598fcf3ce44SJohn Forte 
2599fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
26008f23e9faSHans Rosenfeld 		    "ABORT_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2601fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
260282527734SSukumar Swaminathan 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2603291a2b48SSukumar Swaminathan 		    iocb->un.acxri.parm, iocbq->sbp);
2604fcf3ce44SJohn Forte 
2605291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
26068f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
260782527734SSukumar Swaminathan 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2608291a2b48SSukumar Swaminathan 		}
2609291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2610fcf3ce44SJohn Forte 		break;
2611fcf3ce44SJohn Forte 
2612fcf3ce44SJohn Forte 	case CMD_XRI_ABORTED_CX:	/* Handle ABORT condition */
2613fcf3ce44SJohn Forte 
2614fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
26158f23e9faSHans Rosenfeld 		    "XRI_ABORTED_CX: rpi=%d iotag=%d status=%x parm=%x",
2616fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
261782527734SSukumar Swaminathan 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2618291a2b48SSukumar Swaminathan 		    iocb->un.acxri.parm);
2619fcf3ce44SJohn Forte 
2620291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
26218f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
262282527734SSukumar Swaminathan 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2623291a2b48SSukumar Swaminathan 		}
2624291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2625fcf3ce44SJohn Forte 		break;
2626fcf3ce44SJohn Forte 
2627fcf3ce44SJohn Forte 	case CMD_CLOSE_XRI_CN:	/* Handle CLOSE condition */
2628fcf3ce44SJohn Forte 
2629fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
26308f23e9faSHans Rosenfeld 		    "CLOSE_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2631fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
263282527734SSukumar Swaminathan 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2633291a2b48SSukumar Swaminathan 		    iocb->un.acxri.parm);
2634fcf3ce44SJohn Forte 
2635291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
26368f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
263782527734SSukumar Swaminathan 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2638291a2b48SSukumar Swaminathan 		}
2639291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2640fcf3ce44SJohn Forte 		break;
2641fcf3ce44SJohn Forte 
2642fcf3ce44SJohn Forte 	case CMD_CLOSE_XRI_CX:	/* Handle CLOSE condition */
2643fcf3ce44SJohn Forte 
2644fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
26458f23e9faSHans Rosenfeld 		    "CLOSE_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2646fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
264782527734SSukumar Swaminathan 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2648291a2b48SSukumar Swaminathan 		    iocb->un.acxri.parm, iocbq->sbp);
2649fcf3ce44SJohn Forte 
2650291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
26518f23e9faSHans Rosenfeld 		if (port->mode == MODE_TARGET) {
265282527734SSukumar Swaminathan 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2653291a2b48SSukumar Swaminathan 		}
2654291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
2655fcf3ce44SJohn Forte 		break;
2656fcf3ce44SJohn Forte 
2657fcf3ce44SJohn Forte 	case CMD_ADAPTER_MSG:
2658fcf3ce44SJohn Forte 		/* Allows debug adapter firmware messages to print on host */
2659fcf3ce44SJohn Forte 		bzero(buffer, sizeof (buffer));
2660fcf3ce44SJohn Forte 		bcopy((uint8_t *)iocb, buffer, MAX_MSG_DATA);
2661fcf3ce44SJohn Forte 
2662fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_msg, "%s", buffer);
2663fcf3ce44SJohn Forte 
2664fcf3ce44SJohn Forte 		break;
2665fcf3ce44SJohn Forte 
2666fcf3ce44SJohn Forte 	case CMD_QUE_RING_LIST64_CN:
2667fcf3ce44SJohn Forte 	case CMD_QUE_RING_BUF64_CN:
2668fcf3ce44SJohn Forte 		break;
2669fcf3ce44SJohn Forte 
2670fcf3ce44SJohn Forte 	case CMD_ASYNC_STATUS:
267182527734SSukumar Swaminathan 		emlxs_handle_async_event(hba, cp, iocbq);
2672fcf3ce44SJohn Forte 		break;
2673fcf3ce44SJohn Forte 
26748f23e9faSHans Rosenfeld 	case CMD_XMIT_BLS_RSP64_CX:
26758f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
26768f23e9faSHans Rosenfeld 		    "CMD_XMIT_BLS_RSP64_CX: sbp = %p", sbp);
26778f23e9faSHans Rosenfeld 
26788f23e9faSHans Rosenfeld 		/*
26798f23e9faSHans Rosenfeld 		 * The exchange should have been already freed in the wqe_cmpl
26808f23e9faSHans Rosenfeld 		 * so just free up the pkt here.
26818f23e9faSHans Rosenfeld 		 */
26828f23e9faSHans Rosenfeld 		pkt = PRIV2PKT(sbp);
26838f23e9faSHans Rosenfeld 		emlxs_pkt_free(pkt);
26848f23e9faSHans Rosenfeld 		break;
26858f23e9faSHans Rosenfeld 
2686fcf3ce44SJohn Forte 	default:
26878f23e9faSHans Rosenfeld 		if (iocb->ULPCOMMAND == 0) {
26888f23e9faSHans Rosenfeld 			break;
26898f23e9faSHans Rosenfeld 		}
26908f23e9faSHans Rosenfeld 
2691fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
26928f23e9faSHans Rosenfeld 		    "cmd=%x status=%x iotag=%d context=%x", iocb->ULPCOMMAND,
269382527734SSukumar Swaminathan 		    iocb->ULPSTATUS, iocb->ULPIOTAG, iocb->ULPCONTEXT);
2694fcf3ce44SJohn Forte 
2695fcf3ce44SJohn Forte 		break;
269682527734SSukumar Swaminathan 	}	/* switch(entry->ULPCOMMAND) */
2697fcf3ce44SJohn Forte 
2698fcf3ce44SJohn Forte 	return;
2699fcf3ce44SJohn Forte 
270082527734SSukumar Swaminathan } /* emlxs_proc_channel_event() */
2701fcf3ce44SJohn Forte 
2702fcf3ce44SJohn Forte 
2703291a2b48SSukumar Swaminathan extern char *
2704291a2b48SSukumar Swaminathan emlxs_ffstate_xlate(uint32_t state)
2705fcf3ce44SJohn Forte {
2706291a2b48SSukumar Swaminathan 	static char buffer[32];
2707291a2b48SSukumar Swaminathan 	uint32_t i;
2708291a2b48SSukumar Swaminathan 	uint32_t count;
2709fcf3ce44SJohn Forte 
2710291a2b48SSukumar Swaminathan 	count = sizeof (emlxs_ffstate_table) / sizeof (emlxs_table_t);
2711291a2b48SSukumar Swaminathan 	for (i = 0; i < count; i++) {
2712291a2b48SSukumar Swaminathan 		if (state == emlxs_ffstate_table[i].code) {
2713291a2b48SSukumar Swaminathan 			return (emlxs_ffstate_table[i].string);
2714fcf3ce44SJohn Forte 		}
2715fcf3ce44SJohn Forte 	}
2716fcf3ce44SJohn Forte 
27178f23e9faSHans Rosenfeld 	(void) snprintf(buffer, sizeof (buffer), "state=0x%x", state);
2718291a2b48SSukumar Swaminathan 	return (buffer);
2719fcf3ce44SJohn Forte 
272082527734SSukumar Swaminathan } /* emlxs_ffstate_xlate() */
2721fcf3ce44SJohn Forte 
2722fcf3ce44SJohn Forte 
2723fcf3ce44SJohn Forte extern char *
2724fcf3ce44SJohn Forte emlxs_ring_xlate(uint32_t ringno)
2725fcf3ce44SJohn Forte {
2726fcf3ce44SJohn Forte 	static char buffer[32];
2727fcf3ce44SJohn Forte 	uint32_t i;
2728fcf3ce44SJohn Forte 	uint32_t count;
2729fcf3ce44SJohn Forte 
2730fcf3ce44SJohn Forte 	count = sizeof (emlxs_ring_table) / sizeof (emlxs_table_t);
2731fcf3ce44SJohn Forte 	for (i = 0; i < count; i++) {
2732fcf3ce44SJohn Forte 		if (ringno == emlxs_ring_table[i].code) {
2733fcf3ce44SJohn Forte 			return (emlxs_ring_table[i].string);
2734fcf3ce44SJohn Forte 		}
2735fcf3ce44SJohn Forte 	}
2736fcf3ce44SJohn Forte 
27378f23e9faSHans Rosenfeld 	(void) snprintf(buffer, sizeof (buffer), "ring=0x%x", ringno);
2738fcf3ce44SJohn Forte 	return (buffer);
2739fcf3ce44SJohn Forte 
274082527734SSukumar Swaminathan } /* emlxs_ring_xlate() */
2741fcf3ce44SJohn Forte 
2742fcf3ce44SJohn Forte 
2743a9800bebSGarrett D'Amore extern char *
2744a9800bebSGarrett D'Amore emlxs_pci_cap_xlate(uint32_t id)
2745a9800bebSGarrett D'Amore {
2746a9800bebSGarrett D'Amore 	static char buffer[32];
2747a9800bebSGarrett D'Amore 	uint32_t i;
2748a9800bebSGarrett D'Amore 	uint32_t count;
2749a9800bebSGarrett D'Amore 
2750a9800bebSGarrett D'Amore 	count = sizeof (emlxs_pci_cap) / sizeof (emlxs_table_t);
2751a9800bebSGarrett D'Amore 	for (i = 0; i < count; i++) {
2752a9800bebSGarrett D'Amore 		if (id == emlxs_pci_cap[i].code) {
2753a9800bebSGarrett D'Amore 			return (emlxs_pci_cap[i].string);
2754a9800bebSGarrett D'Amore 		}
2755a9800bebSGarrett D'Amore 	}
2756a9800bebSGarrett D'Amore 
27578f23e9faSHans Rosenfeld 	(void) snprintf(buffer, sizeof (buffer), "PCI_CAP_ID_%02X", id);
2758a9800bebSGarrett D'Amore 	return (buffer);
2759a9800bebSGarrett D'Amore 
2760a9800bebSGarrett D'Amore } /* emlxs_pci_cap_xlate() */
2761a9800bebSGarrett D'Amore 
2762fcf3ce44SJohn Forte 
27638f23e9faSHans Rosenfeld extern char *
27648f23e9faSHans Rosenfeld emlxs_pci_ecap_xlate(uint32_t id)
27658f23e9faSHans Rosenfeld {
27668f23e9faSHans Rosenfeld 	static char buffer[32];
27678f23e9faSHans Rosenfeld 	uint32_t i;
27688f23e9faSHans Rosenfeld 	uint32_t count;
27698f23e9faSHans Rosenfeld 
27708f23e9faSHans Rosenfeld 	count = sizeof (emlxs_pci_ecap) / sizeof (emlxs_table_t);
27718f23e9faSHans Rosenfeld 	for (i = 0; i < count; i++) {
27728f23e9faSHans Rosenfeld 		if (id == emlxs_pci_ecap[i].code) {
27738f23e9faSHans Rosenfeld 			return (emlxs_pci_ecap[i].string);
27748f23e9faSHans Rosenfeld 		}
27758f23e9faSHans Rosenfeld 	}
27768f23e9faSHans Rosenfeld 
27778f23e9faSHans Rosenfeld 	(void) snprintf(buffer, sizeof (buffer), "PCI_EXT_CAP_ID_%02X", id);
27788f23e9faSHans Rosenfeld 	return (buffer);
27798f23e9faSHans Rosenfeld 
27808f23e9faSHans Rosenfeld } /* emlxs_pci_ecap_xlate() */
27818f23e9faSHans Rosenfeld 
27828f23e9faSHans Rosenfeld 
2783fcf3ce44SJohn Forte extern void
2784fcf3ce44SJohn Forte emlxs_pcix_mxr_update(emlxs_hba_t *hba, uint32_t verbose)
2785fcf3ce44SJohn Forte {
2786fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
278782527734SSukumar Swaminathan 	MAILBOXQ *mbq;
2788fcf3ce44SJohn Forte 	MAILBOX *mb;
2789fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
2790fcf3ce44SJohn Forte 	uint32_t value;
2791fcf3ce44SJohn Forte 
2792fcf3ce44SJohn Forte 	cfg = &CFG;
2793fcf3ce44SJohn Forte 
2794fcf3ce44SJohn Forte xlate:
2795fcf3ce44SJohn Forte 
2796fcf3ce44SJohn Forte 	switch (cfg[CFG_PCI_MAX_READ].current) {
2797fcf3ce44SJohn Forte 	case 512:
2798fcf3ce44SJohn Forte 		value = 0;
2799fcf3ce44SJohn Forte 		break;
2800fcf3ce44SJohn Forte 
2801fcf3ce44SJohn Forte 	case 1024:
2802fcf3ce44SJohn Forte 		value = 1;
2803fcf3ce44SJohn Forte 		break;
2804fcf3ce44SJohn Forte 
2805fcf3ce44SJohn Forte 	case 2048:
2806fcf3ce44SJohn Forte 		value = 2;
2807fcf3ce44SJohn Forte 		break;
2808fcf3ce44SJohn Forte 
2809fcf3ce44SJohn Forte 	case 4096:
2810fcf3ce44SJohn Forte 		value = 3;
2811fcf3ce44SJohn Forte 		break;
2812fcf3ce44SJohn Forte 
2813fcf3ce44SJohn Forte 	default:
2814fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2815fcf3ce44SJohn Forte 		    "PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
2816fcf3ce44SJohn Forte 		    cfg[CFG_PCI_MAX_READ].current, cfg[CFG_PCI_MAX_READ].def);
2817fcf3ce44SJohn Forte 
2818fcf3ce44SJohn Forte 		cfg[CFG_PCI_MAX_READ].current = cfg[CFG_PCI_MAX_READ].def;
2819fcf3ce44SJohn Forte 		goto xlate;
2820fcf3ce44SJohn Forte 	}
2821fcf3ce44SJohn Forte 
28228f23e9faSHans Rosenfeld 	if ((mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)),
28238f23e9faSHans Rosenfeld 	    KM_SLEEP)) == 0) {
2824fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2825fcf3ce44SJohn Forte 		    "PCI_MAX_READ: Unable to allocate mailbox buffer.");
2826fcf3ce44SJohn Forte 		return;
2827fcf3ce44SJohn Forte 	}
282882527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
2829fcf3ce44SJohn Forte 
283082527734SSukumar Swaminathan 	emlxs_mb_set_var(hba, mbq, 0x00100506, value);
2831291a2b48SSukumar Swaminathan 
283282527734SSukumar Swaminathan 	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2833fcf3ce44SJohn Forte 		if (verbose || (mb->mbxStatus != 0x12)) {
2834fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2835291a2b48SSukumar Swaminathan 			    "PCI_MAX_READ: Unable to update. "
2836291a2b48SSukumar Swaminathan 			    "status=%x value=%d (%d bytes)",
2837291a2b48SSukumar Swaminathan 			    mb->mbxStatus, value,
2838fcf3ce44SJohn Forte 			    cfg[CFG_PCI_MAX_READ].current);
2839fcf3ce44SJohn Forte 		}
2840fcf3ce44SJohn Forte 	} else {
2841291a2b48SSukumar Swaminathan 		if (verbose &&
2842291a2b48SSukumar Swaminathan 		    (cfg[CFG_PCI_MAX_READ].current !=
2843fcf3ce44SJohn Forte 		    cfg[CFG_PCI_MAX_READ].def)) {
2844fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2845fcf3ce44SJohn Forte 			    "PCI_MAX_READ: Updated. %d bytes",
2846fcf3ce44SJohn Forte 			    cfg[CFG_PCI_MAX_READ].current);
2847fcf3ce44SJohn Forte 		}
2848fcf3ce44SJohn Forte 	}
2849fcf3ce44SJohn Forte 
28508f23e9faSHans Rosenfeld 	(void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
2851fcf3ce44SJohn Forte 
2852fcf3ce44SJohn Forte 	return;
2853fcf3ce44SJohn Forte 
285482527734SSukumar Swaminathan } /* emlxs_pcix_mxr_update */
2855fcf3ce44SJohn Forte 
2856fcf3ce44SJohn Forte 
2857fcf3ce44SJohn Forte 
2858fcf3ce44SJohn Forte extern uint32_t
285982527734SSukumar Swaminathan emlxs_get_key(emlxs_hba_t *hba, MAILBOXQ *mbq)
2860fcf3ce44SJohn Forte {
2861fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
286282527734SSukumar Swaminathan 	MAILBOX *mb = (MAILBOX *)mbq;
2863fcf3ce44SJohn Forte 	uint32_t npname0, npname1;
2864fcf3ce44SJohn Forte 	uint32_t tmpkey, theKey;
2865fcf3ce44SJohn Forte 	uint16_t key850;
2866fcf3ce44SJohn Forte 	uint32_t t1, t2, t3, t4;
2867fcf3ce44SJohn Forte 	uint32_t ts;
2868fcf3ce44SJohn Forte 
2869fcf3ce44SJohn Forte #define	SEED 0x876EDC21
2870fcf3ce44SJohn Forte 
2871fcf3ce44SJohn Forte 	/* This key is only used currently for SBUS adapters */
2872fcf3ce44SJohn Forte 	if (hba->bus_type != SBUS_FC) {
2873fcf3ce44SJohn Forte 		return (0);
2874fcf3ce44SJohn Forte 	}
2875291a2b48SSukumar Swaminathan 
2876fcf3ce44SJohn Forte 	tmpkey = mb->un.varWords[30];
287782527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE(hba, FC_INIT_NVPARAMS);
2878fcf3ce44SJohn Forte 
287982527734SSukumar Swaminathan 	emlxs_mb_read_nv(hba, mbq);
288082527734SSukumar Swaminathan 	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2881fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2882291a2b48SSukumar Swaminathan 		    "Unable to read nvram. cmd=%x status=%x", mb->mbxCommand,
2883291a2b48SSukumar Swaminathan 		    mb->mbxStatus);
2884fcf3ce44SJohn Forte 
2885fcf3ce44SJohn Forte 		return (0);
2886fcf3ce44SJohn Forte 	}
2887fcf3ce44SJohn Forte 	npname0 = mb->un.varRDnvp.portname[0];
2888fcf3ce44SJohn Forte 	npname1 = mb->un.varRDnvp.portname[1];
2889fcf3ce44SJohn Forte 
2890fcf3ce44SJohn Forte 	key850 = (uint16_t)((tmpkey & 0x00FFFF00) >> 8);
2891fcf3ce44SJohn Forte 	ts = (uint16_t)(npname1 + 1);
2892fcf3ce44SJohn Forte 	t1 = ts * key850;
2893fcf3ce44SJohn Forte 	ts = (uint16_t)((npname1 >> 16) + 1);
2894fcf3ce44SJohn Forte 	t2 = ts * key850;
2895fcf3ce44SJohn Forte 	ts = (uint16_t)(npname0 + 1);
2896fcf3ce44SJohn Forte 	t3 = ts * key850;
2897fcf3ce44SJohn Forte 	ts = (uint16_t)((npname0 >> 16) + 1);
2898fcf3ce44SJohn Forte 	t4 = ts * key850;
2899fcf3ce44SJohn Forte 	theKey = SEED + t1 + t2 + t3 + t4;
2900fcf3ce44SJohn Forte 
2901fcf3ce44SJohn Forte 	return (theKey);
2902fcf3ce44SJohn Forte 
290382527734SSukumar Swaminathan } /* emlxs_get_key() */
2904291a2b48SSukumar Swaminathan 
2905291a2b48SSukumar Swaminathan 
2906291a2b48SSukumar Swaminathan extern void
2907291a2b48SSukumar Swaminathan emlxs_fw_show(emlxs_hba_t *hba)
2908291a2b48SSukumar Swaminathan {
2909291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
2910291a2b48SSukumar Swaminathan 	uint32_t i;
2911291a2b48SSukumar Swaminathan 
2912291a2b48SSukumar Swaminathan 	/* Display firmware library one time */
291382527734SSukumar Swaminathan 	for (i = 0; i < emlxs_fw_count; i++) {
2914291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_library_msg, "%s",
2915291a2b48SSukumar Swaminathan 		    emlxs_fw_table[i].label);
2916291a2b48SSukumar Swaminathan 	}
2917291a2b48SSukumar Swaminathan 
2918291a2b48SSukumar Swaminathan 	return;
2919291a2b48SSukumar Swaminathan 
292082527734SSukumar Swaminathan } /* emlxs_fw_show() */
2921291a2b48SSukumar Swaminathan 
2922291a2b48SSukumar Swaminathan 
2923291a2b48SSukumar Swaminathan #ifdef MODFW_SUPPORT
292482527734SSukumar Swaminathan extern void
2925291a2b48SSukumar Swaminathan emlxs_fw_load(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2926291a2b48SSukumar Swaminathan {
2927291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
2928291a2b48SSukumar Swaminathan 	int (*emlxs_fw_get)(emlxs_firmware_t *);
2929291a2b48SSukumar Swaminathan 	int err;
29308f23e9faSHans Rosenfeld 	char name[64];
2931291a2b48SSukumar Swaminathan 
2932291a2b48SSukumar Swaminathan 	/* Make sure image is unloaded and image buffer pointer is clear */
2933291a2b48SSukumar Swaminathan 	emlxs_fw_unload(hba, fw);
2934291a2b48SSukumar Swaminathan 
2935291a2b48SSukumar Swaminathan 	err = 0;
2936291a2b48SSukumar Swaminathan 	hba->fw_modhandle =
2937291a2b48SSukumar Swaminathan 	    ddi_modopen(EMLXS_FW_MODULE, KRTLD_MODE_FIRST, &err);
2938291a2b48SSukumar Swaminathan 	if (!hba->fw_modhandle) {
2939291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2940291a2b48SSukumar Swaminathan 		    "Unable to load firmware module. error=%d", err);
2941291a2b48SSukumar Swaminathan 
2942291a2b48SSukumar Swaminathan 		return;
2943291a2b48SSukumar Swaminathan 	} else {
2944291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2945291a2b48SSukumar Swaminathan 		    "Firmware module loaded.");
2946291a2b48SSukumar Swaminathan 	}
2947291a2b48SSukumar Swaminathan 
29488f23e9faSHans Rosenfeld 	(void) snprintf(name, sizeof (name), "%s_fw_get", DRIVER_NAME);
2949291a2b48SSukumar Swaminathan 	err = 0;
2950291a2b48SSukumar Swaminathan 	emlxs_fw_get =
29518f23e9faSHans Rosenfeld 	    (int (*)())ddi_modsym(hba->fw_modhandle, name, &err);
2952291a2b48SSukumar Swaminathan 	if ((void *)emlxs_fw_get == NULL) {
2953291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
29548f23e9faSHans Rosenfeld 		    "%s not present. error=%d", name, err);
2955291a2b48SSukumar Swaminathan 
2956291a2b48SSukumar Swaminathan 		emlxs_fw_unload(hba, fw);
2957291a2b48SSukumar Swaminathan 		return;
2958291a2b48SSukumar Swaminathan 	}
2959291a2b48SSukumar Swaminathan 
2960291a2b48SSukumar Swaminathan 	if (emlxs_fw_get(fw)) {
2961291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2962291a2b48SSukumar Swaminathan 		    "Invalid firmware image module found. %s", fw->label);
2963291a2b48SSukumar Swaminathan 
2964291a2b48SSukumar Swaminathan 		emlxs_fw_unload(hba, fw);
2965291a2b48SSukumar Swaminathan 		return;
2966291a2b48SSukumar Swaminathan 	}
2967291a2b48SSukumar Swaminathan 
2968291a2b48SSukumar Swaminathan 	return;
2969291a2b48SSukumar Swaminathan 
297082527734SSukumar Swaminathan } /* emlxs_fw_load() */
2971291a2b48SSukumar Swaminathan 
2972291a2b48SSukumar Swaminathan 
297382527734SSukumar Swaminathan extern void
2974291a2b48SSukumar Swaminathan emlxs_fw_unload(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2975291a2b48SSukumar Swaminathan {
2976291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
2977291a2b48SSukumar Swaminathan 
2978291a2b48SSukumar Swaminathan 	/* Clear the firmware image */
2979291a2b48SSukumar Swaminathan 	fw->image = NULL;
2980291a2b48SSukumar Swaminathan 	fw->size = 0;
2981291a2b48SSukumar Swaminathan 
2982291a2b48SSukumar Swaminathan 	if (hba->fw_modhandle) {
2983291a2b48SSukumar Swaminathan 		/* Close the module */
2984291a2b48SSukumar Swaminathan 		(void) ddi_modclose(hba->fw_modhandle);
2985291a2b48SSukumar Swaminathan 		hba->fw_modhandle = NULL;
2986291a2b48SSukumar Swaminathan 
2987291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2988291a2b48SSukumar Swaminathan 		    "Firmware module unloaded.");
2989291a2b48SSukumar Swaminathan 	}
2990291a2b48SSukumar Swaminathan 
2991291a2b48SSukumar Swaminathan 	return;
2992291a2b48SSukumar Swaminathan 
299382527734SSukumar Swaminathan } /* emlxs_fw_unload() */
2994291a2b48SSukumar Swaminathan #endif /* MODFW_SUPPORT */
2995a9800bebSGarrett D'Amore 
2996a9800bebSGarrett D'Amore 
2997a9800bebSGarrett D'Amore static void
2998a9800bebSGarrett D'Amore emlxs_pci_cap_offsets(emlxs_hba_t *hba)
2999a9800bebSGarrett D'Amore {
3000a9800bebSGarrett D'Amore 	emlxs_port_t *port = &PPORT;
30018f23e9faSHans Rosenfeld 	uint32_t reg;
3002a9800bebSGarrett D'Amore 	uint8_t	offset;
30038f23e9faSHans Rosenfeld 	uint8_t	next;
3004a9800bebSGarrett D'Amore 	uint8_t	id;
30058f23e9faSHans Rosenfeld 	uint16_t eoffset;
30068f23e9faSHans Rosenfeld 	uint16_t enext;
30078f23e9faSHans Rosenfeld 	uint8_t eversion;
30088f23e9faSHans Rosenfeld 	uint16_t eid;
30098f23e9faSHans Rosenfeld 
30108f23e9faSHans Rosenfeld 	/* Read PCI capbabilities */
3011a9800bebSGarrett D'Amore 
3012a9800bebSGarrett D'Amore 	bzero(hba->pci_cap_offset, sizeof (hba->pci_cap_offset));
3013a9800bebSGarrett D'Amore 
3014a9800bebSGarrett D'Amore 	/* Read first offset */
30158f23e9faSHans Rosenfeld 	offset = PCI_CAP_POINTER;
3016a9800bebSGarrett D'Amore 	offset = ddi_get8(hba->pci_acc_handle,
30178f23e9faSHans Rosenfeld 	    (uint8_t *)(hba->pci_addr + offset));
3018a9800bebSGarrett D'Amore 
3019a9800bebSGarrett D'Amore 	while (offset >= PCI_CAP_PTR_OFF) {
30208f23e9faSHans Rosenfeld 		/* Read the cap */
30218f23e9faSHans Rosenfeld 		reg = ddi_get32(hba->pci_acc_handle,
30228f23e9faSHans Rosenfeld 		    (uint32_t *)(hba->pci_addr + offset));
30238f23e9faSHans Rosenfeld 
30248f23e9faSHans Rosenfeld 		id = ((reg >> PCI_CAP_ID_SHIFT) & PCI_CAP_ID_MASK);
30258f23e9faSHans Rosenfeld 		next = ((reg >> PCI_CAP_NEXT_PTR_SHIFT) &
30268f23e9faSHans Rosenfeld 		    PCI_CAP_NEXT_PTR_MASK);
3027a9800bebSGarrett D'Amore 
30288f23e9faSHans Rosenfeld 		if ((id < PCI_CAP_MAX_PTR) &&
30298f23e9faSHans Rosenfeld 		    (hba->pci_cap_offset[id] == 0)) {
3030a9800bebSGarrett D'Amore 			hba->pci_cap_offset[id] = offset;
3031a9800bebSGarrett D'Amore 		}
3032a9800bebSGarrett D'Amore 
3033a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
30348f23e9faSHans Rosenfeld 		    "%s: offset=0x%x next=0x%x",
30358f23e9faSHans Rosenfeld 		    emlxs_pci_cap_xlate(id), offset, next);
30368f23e9faSHans Rosenfeld 
30378f23e9faSHans Rosenfeld 		offset = next;
30388f23e9faSHans Rosenfeld 	}
30398f23e9faSHans Rosenfeld 
30408f23e9faSHans Rosenfeld 	/* Workaround for BE adapters */
30418f23e9faSHans Rosenfeld 	if ((hba->pci_cap_offset[PCI_CAP_ID_VS] == 0) &&
30428f23e9faSHans Rosenfeld 	    (hba->model_info.chip & EMLXS_BE_CHIPS)) {
30438f23e9faSHans Rosenfeld 		hba->pci_cap_offset[PCI_CAP_ID_VS] = 0x54;
30448f23e9faSHans Rosenfeld 
30458f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
30468f23e9faSHans Rosenfeld 		    "%s: offset=0x%x  Added.",
30478f23e9faSHans Rosenfeld 		    emlxs_pci_cap_xlate(PCI_CAP_ID_VS),
30488f23e9faSHans Rosenfeld 		    hba->pci_cap_offset[PCI_CAP_ID_VS]);
30498f23e9faSHans Rosenfeld 	}
30508f23e9faSHans Rosenfeld 
30518f23e9faSHans Rosenfeld 	if (! hba->pci_cap_offset[PCI_CAP_ID_PCI_E]) {
30528f23e9faSHans Rosenfeld 		/* It's not a PCIE adapter. */
30538f23e9faSHans Rosenfeld 		return;
30548f23e9faSHans Rosenfeld 	}
30558f23e9faSHans Rosenfeld 
30568f23e9faSHans Rosenfeld 	/* Read PCI Extended capbabilities */
30578f23e9faSHans Rosenfeld 
30588f23e9faSHans Rosenfeld 	bzero(hba->pci_ecap_offset, sizeof (hba->pci_ecap_offset));
30598f23e9faSHans Rosenfeld 
30608f23e9faSHans Rosenfeld 	/* Set first offset */
30618f23e9faSHans Rosenfeld 	eoffset = PCIE_EXT_CAP;
30628f23e9faSHans Rosenfeld 
30638f23e9faSHans Rosenfeld 	while (eoffset >= PCIE_EXT_CAP) {
30648f23e9faSHans Rosenfeld 		/* Read the cap */
30658f23e9faSHans Rosenfeld 		reg = ddi_get32(hba->pci_acc_handle,
30668f23e9faSHans Rosenfeld 		    (uint32_t *)(hba->pci_addr + eoffset));
30678f23e9faSHans Rosenfeld 
30688f23e9faSHans Rosenfeld 		eid = ((reg >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK);
30698f23e9faSHans Rosenfeld 		eversion = ((reg >> PCIE_EXT_CAP_VER_SHIFT) &
30708f23e9faSHans Rosenfeld 		    PCIE_EXT_CAP_VER_MASK);
30718f23e9faSHans Rosenfeld 		enext = ((reg >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
30728f23e9faSHans Rosenfeld 		    PCIE_EXT_CAP_NEXT_PTR_MASK);
30738f23e9faSHans Rosenfeld 
30748f23e9faSHans Rosenfeld 		if ((eid < PCI_EXT_CAP_MAX_PTR) &&
30758f23e9faSHans Rosenfeld 		    (hba->pci_ecap_offset[eid] == 0)) {
30768f23e9faSHans Rosenfeld 			hba->pci_ecap_offset[eid] = eoffset;
30778f23e9faSHans Rosenfeld 		}
30788f23e9faSHans Rosenfeld 
30798f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
30808f23e9faSHans Rosenfeld 		    "%s: offset=0x%x version=0x%x next=0x%x",
30818f23e9faSHans Rosenfeld 		    emlxs_pci_ecap_xlate(eid),
30828f23e9faSHans Rosenfeld 		    eoffset, eversion, enext);
3083a9800bebSGarrett D'Amore 
30848f23e9faSHans Rosenfeld 		eoffset = enext;
3085a9800bebSGarrett D'Amore 	}
3086a9800bebSGarrett D'Amore 
3087a9800bebSGarrett D'Amore 	return;
3088a9800bebSGarrett D'Amore 
3089a9800bebSGarrett D'Amore } /* emlxs_pci_cap_offsets() */
3090