1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte 
22*fcf3ce44SJohn Forte /*
23*fcf3ce44SJohn Forte  * Copyright 2008 Emulex.  All rights reserved.
24*fcf3ce44SJohn Forte  * Use is subject to License terms.
25*fcf3ce44SJohn Forte  */
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte 
28*fcf3ce44SJohn Forte #define	EMLXS_MODEL_DEF
29*fcf3ce44SJohn Forte 
30*fcf3ce44SJohn Forte #include "emlxs.h"
31*fcf3ce44SJohn Forte 
32*fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
33*fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_HBA_C);
34*fcf3ce44SJohn Forte 
35*fcf3ce44SJohn Forte static void emlxs_proc_attention(emlxs_hba_t *hba, uint32_t ha_copy);
36*fcf3ce44SJohn Forte static uint32_t emlxs_get_attention(emlxs_hba_t *hba, uint32_t msgid);
37*fcf3ce44SJohn Forte static void emlxs_handle_link_event(emlxs_hba_t *hba);
38*fcf3ce44SJohn Forte static void emlxs_handle_ring_event(emlxs_hba_t *hba, int32_t ring,
39*fcf3ce44SJohn Forte     uint32_t ha_copy);
40*fcf3ce44SJohn Forte static uint32_t emlxs_decode_biu_rev(uint32_t rev);
41*fcf3ce44SJohn Forte static uint32_t emlxs_decode_endec_rev(uint32_t rev);
42*fcf3ce44SJohn Forte static void emlxs_parse_prog_types(emlxs_hba_t *hba, char *types);
43*fcf3ce44SJohn Forte static int32_t emlxs_hba_init(emlxs_hba_t *hba);
44*fcf3ce44SJohn Forte static int32_t emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd, uint32_t size);
45*fcf3ce44SJohn Forte static void emlxs_proc_ring_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq);
46*fcf3ce44SJohn Forte static void emlxs_issue_iocb(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq);
47*fcf3ce44SJohn Forte static void emlxs_build_prog_types(emlxs_hba_t *hba, char *prog_types);
48*fcf3ce44SJohn Forte static void emlxs_handle_async_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq);
49*fcf3ce44SJohn Forte static void emlxs_process_link_speed(emlxs_hba_t *hba);
50*fcf3ce44SJohn Forte static int emlxs_handle_rcv_seq(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq);
51*fcf3ce44SJohn Forte static void emlxs_decode_label(char *label, char *buffer);
52*fcf3ce44SJohn Forte 
53*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
54*fcf3ce44SJohn Forte static uint32_t emlxs_msi_intr(char *arg1, char *arg2);
55*fcf3ce44SJohn Forte uint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
56*fcf3ce44SJohn Forte {
57*fcf3ce44SJohn Forte 	EMLXS_MSI_MAP1,
58*fcf3ce44SJohn Forte 	EMLXS_MSI_MAP2,
59*fcf3ce44SJohn Forte 	EMLXS_MSI_MAP4,
60*fcf3ce44SJohn Forte 	EMLXS_MSI_MAP8
61*fcf3ce44SJohn Forte };
62*fcf3ce44SJohn Forte uint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
63*fcf3ce44SJohn Forte {
64*fcf3ce44SJohn Forte 	EMLXS_MSI0_MASK1,
65*fcf3ce44SJohn Forte 	EMLXS_MSI0_MASK2,
66*fcf3ce44SJohn Forte 	EMLXS_MSI0_MASK4,
67*fcf3ce44SJohn Forte 	EMLXS_MSI0_MASK8
68*fcf3ce44SJohn Forte };
69*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
70*fcf3ce44SJohn Forte 
71*fcf3ce44SJohn Forte static int32_t emlxs_intx_intr(char *arg);
72*fcf3ce44SJohn Forte 
73*fcf3ce44SJohn Forte 
74*fcf3ce44SJohn Forte static uint32_t emlxs_disable_traffic_cop = 1;
75*fcf3ce44SJohn Forte 
76*fcf3ce44SJohn Forte emlxs_table_t emlxs_ring_table[] =
77*fcf3ce44SJohn Forte {
78*fcf3ce44SJohn Forte 	{FC_FCP_RING, "FCP Ring"},
79*fcf3ce44SJohn Forte 	{FC_IP_RING, "IP  Ring"},
80*fcf3ce44SJohn Forte 	{FC_ELS_RING, "ELS Ring"},
81*fcf3ce44SJohn Forte 	{FC_CT_RING, "CT  Ring"}
82*fcf3ce44SJohn Forte 
83*fcf3ce44SJohn Forte };	/* emlxs_ring_table */
84*fcf3ce44SJohn Forte 
85*fcf3ce44SJohn Forte 
86*fcf3ce44SJohn Forte emlxs_table_t emlxs_ffstate_table[] =
87*fcf3ce44SJohn Forte {
88*fcf3ce44SJohn Forte 	{0, "NULL"},
89*fcf3ce44SJohn Forte 	{FC_ERROR, "ERROR"},
90*fcf3ce44SJohn Forte 	{FC_KILLED, "KILLED"},
91*fcf3ce44SJohn Forte 	{FC_WARM_START, "WARM_START"},
92*fcf3ce44SJohn Forte 	{FC_INIT_START, "INIT_START"},
93*fcf3ce44SJohn Forte 	{FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
94*fcf3ce44SJohn Forte 	{FC_INIT_REV, "INIT_REV"},
95*fcf3ce44SJohn Forte 	{FC_INIT_CFGPORT, "INIT_CFGPORT"},
96*fcf3ce44SJohn Forte 	{FC_INIT_CFGRING, "INIT_CFGRING"},
97*fcf3ce44SJohn Forte 	{FC_INIT_INITLINK, "INIT_INITLINK"},
98*fcf3ce44SJohn Forte 	{FC_LINK_DOWN, "LINK_DOWN"},
99*fcf3ce44SJohn Forte 	{FC_LINK_UP, "LINK_UP"},
100*fcf3ce44SJohn Forte 	{FC_CLEAR_LA, "CLEAR_LA"},
101*fcf3ce44SJohn Forte 	{FC_READY, "READY"}
102*fcf3ce44SJohn Forte 
103*fcf3ce44SJohn Forte };	/* emlxs_ffstate_table */
104*fcf3ce44SJohn Forte 
105*fcf3ce44SJohn Forte 
106*fcf3ce44SJohn Forte 
107*fcf3ce44SJohn Forte /*
108*fcf3ce44SJohn Forte  *
109*fcf3ce44SJohn Forte  * emlxs_ffinit
110*fcf3ce44SJohn Forte  * This routine will start initialization of the FireFly Chipset
111*fcf3ce44SJohn Forte  *
112*fcf3ce44SJohn Forte  */
113*fcf3ce44SJohn Forte extern int
114*fcf3ce44SJohn Forte emlxs_ffinit(emlxs_hba_t *hba)
115*fcf3ce44SJohn Forte {
116*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
117*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
118*fcf3ce44SJohn Forte 	emlxs_vpd_t *vpd;
119*fcf3ce44SJohn Forte 	MAILBOX *mb;
120*fcf3ce44SJohn Forte 	RING *rp;
121*fcf3ce44SJohn Forte 	MATCHMAP *mp;
122*fcf3ce44SJohn Forte 	MATCHMAP *mp1;
123*fcf3ce44SJohn Forte 	uint8_t *inptr;
124*fcf3ce44SJohn Forte 	uint8_t *outptr;
125*fcf3ce44SJohn Forte 	uint32_t status;
126*fcf3ce44SJohn Forte 	uint32_t i;
127*fcf3ce44SJohn Forte 	uint32_t j;
128*fcf3ce44SJohn Forte 	uint32_t read_rev_reset;
129*fcf3ce44SJohn Forte 	uint32_t key = 0;
130*fcf3ce44SJohn Forte 	uint32_t fw_check;
131*fcf3ce44SJohn Forte 	uint32_t rval;
132*fcf3ce44SJohn Forte 	uint32_t offset;
133*fcf3ce44SJohn Forte 	uint8_t vpd_data[DMP_VPD_SIZE];
134*fcf3ce44SJohn Forte 	uint32_t MaxRbusSize;
135*fcf3ce44SJohn Forte 	uint32_t MaxIbusSize;
136*fcf3ce44SJohn Forte 	uint32_t sli_mode;
137*fcf3ce44SJohn Forte 
138*fcf3ce44SJohn Forte 	cfg = &CFG;
139*fcf3ce44SJohn Forte 	vpd = &VPD;
140*fcf3ce44SJohn Forte 	mb = 0;
141*fcf3ce44SJohn Forte 	MaxRbusSize = 0;
142*fcf3ce44SJohn Forte 	MaxIbusSize = 0;
143*fcf3ce44SJohn Forte 	read_rev_reset = 0;
144*fcf3ce44SJohn Forte 	sli_mode = 2;
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
147*fcf3ce44SJohn Forte 	/* Initialize sli mode based on configuration parameter */
148*fcf3ce44SJohn Forte 	switch (cfg[CFG_SLI_MODE].current) {
149*fcf3ce44SJohn Forte 	case 2:	/* SLI2 mode */
150*fcf3ce44SJohn Forte 		sli_mode = 2;
151*fcf3ce44SJohn Forte 		break;
152*fcf3ce44SJohn Forte 
153*fcf3ce44SJohn Forte 	case 0:	/* Best available */
154*fcf3ce44SJohn Forte 	case 1:	/* Best available */
155*fcf3ce44SJohn Forte 	case 3:	/* SLI3 mode */
156*fcf3ce44SJohn Forte 	default:
157*fcf3ce44SJohn Forte 		/* SBUS adapters only available in SLI2 */
158*fcf3ce44SJohn Forte 		if (hba->bus_type == SBUS_FC) {
159*fcf3ce44SJohn Forte 			sli_mode = 2;
160*fcf3ce44SJohn Forte 		} else {
161*fcf3ce44SJohn Forte 			sli_mode = 3;
162*fcf3ce44SJohn Forte 		}
163*fcf3ce44SJohn Forte 		break;
164*fcf3ce44SJohn Forte 	}
165*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
166*fcf3ce44SJohn Forte 
167*fcf3ce44SJohn Forte 	/* Set the fw_check flag */
168*fcf3ce44SJohn Forte 	fw_check = cfg[CFG_FW_CHECK].current;
169*fcf3ce44SJohn Forte 
170*fcf3ce44SJohn Forte 	hba->mbox_queue_flag = 0;
171*fcf3ce44SJohn Forte 	hba->hc_copy = 0;
172*fcf3ce44SJohn Forte 	hba->fc_edtov = FF_DEF_EDTOV;
173*fcf3ce44SJohn Forte 	hba->fc_ratov = FF_DEF_RATOV;
174*fcf3ce44SJohn Forte 	hba->fc_altov = FF_DEF_ALTOV;
175*fcf3ce44SJohn Forte 	hba->fc_arbtov = FF_DEF_ARBTOV;
176*fcf3ce44SJohn Forte 
177*fcf3ce44SJohn Forte reset:
178*fcf3ce44SJohn Forte 
179*fcf3ce44SJohn Forte 	/* Reset and initialize the adapter */
180*fcf3ce44SJohn Forte 	if (emlxs_hba_init(hba)) {
181*fcf3ce44SJohn Forte 		return (EIO);
182*fcf3ce44SJohn Forte 	}
183*fcf3ce44SJohn Forte 	/*
184*fcf3ce44SJohn Forte 	 * Allocate some memory for buffers
185*fcf3ce44SJohn Forte 	 */
186*fcf3ce44SJohn Forte 	if (emlxs_mem_alloc_buffer(hba) == 0) {
187*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
188*fcf3ce44SJohn Forte 		    "Unable to allocate memory buffers.");
189*fcf3ce44SJohn Forte 
190*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
191*fcf3ce44SJohn Forte 
192*fcf3ce44SJohn Forte 		return (ENOMEM);
193*fcf3ce44SJohn Forte 	}
194*fcf3ce44SJohn Forte 	/*
195*fcf3ce44SJohn Forte 	 * Get a buffer which will be used repeatedly for mailbox commands
196*fcf3ce44SJohn Forte 	 */
197*fcf3ce44SJohn Forte 	if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == 0) {
198*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
199*fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
200*fcf3ce44SJohn Forte 
201*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
202*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
203*fcf3ce44SJohn Forte 
204*fcf3ce44SJohn Forte 		return (ENOMEM);
205*fcf3ce44SJohn Forte 	}
206*fcf3ce44SJohn Forte 	/* Check for the LP9802 (This is a special case) */
207*fcf3ce44SJohn Forte 	/* We need to check for dual channel adapter */
208*fcf3ce44SJohn Forte 	if (hba->model_info.device_id == PCI_DEVICE_ID_LP9802) {
209*fcf3ce44SJohn Forte 		/* Try to determine if this is a DC adapter */
210*fcf3ce44SJohn Forte 		if (emlxs_get_max_sram(hba, &MaxRbusSize, &MaxIbusSize) == 0) {
211*fcf3ce44SJohn Forte 			if (MaxRbusSize == REDUCED_SRAM_CFG) {
212*fcf3ce44SJohn Forte 				/* LP9802DC */
213*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
214*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9802DC) {
215*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
216*fcf3ce44SJohn Forte 						    &hba->model_info,
217*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
218*fcf3ce44SJohn Forte 						break;
219*fcf3ce44SJohn Forte 					}
220*fcf3ce44SJohn Forte 				}
221*fcf3ce44SJohn Forte 			} else if (hba->model_info.id != LP9802) {
222*fcf3ce44SJohn Forte 				/* LP9802 */
223*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
224*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9802) {
225*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
226*fcf3ce44SJohn Forte 						    &hba->model_info,
227*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
228*fcf3ce44SJohn Forte 						break;
229*fcf3ce44SJohn Forte 					}
230*fcf3ce44SJohn Forte 				}
231*fcf3ce44SJohn Forte 			}
232*fcf3ce44SJohn Forte 		}
233*fcf3ce44SJohn Forte 	}
234*fcf3ce44SJohn Forte 	/*
235*fcf3ce44SJohn Forte 	 * Setup and issue mailbox READ REV command
236*fcf3ce44SJohn Forte 	 */
237*fcf3ce44SJohn Forte 	vpd->opFwRev = 0;
238*fcf3ce44SJohn Forte 	vpd->postKernRev = 0;
239*fcf3ce44SJohn Forte 	vpd->sli1FwRev = 0;
240*fcf3ce44SJohn Forte 	vpd->sli2FwRev = 0;
241*fcf3ce44SJohn Forte 	vpd->sli3FwRev = 0;
242*fcf3ce44SJohn Forte 	vpd->sli4FwRev = 0;
243*fcf3ce44SJohn Forte 
244*fcf3ce44SJohn Forte 	vpd->postKernName[0] = 0;
245*fcf3ce44SJohn Forte 	vpd->opFwName[0] = 0;
246*fcf3ce44SJohn Forte 	vpd->sli1FwName[0] = 0;
247*fcf3ce44SJohn Forte 	vpd->sli2FwName[0] = 0;
248*fcf3ce44SJohn Forte 	vpd->sli3FwName[0] = 0;
249*fcf3ce44SJohn Forte 	vpd->sli4FwName[0] = 0;
250*fcf3ce44SJohn Forte 
251*fcf3ce44SJohn Forte 	vpd->opFwLabel[0] = 0;
252*fcf3ce44SJohn Forte 	vpd->sli1FwLabel[0] = 0;
253*fcf3ce44SJohn Forte 	vpd->sli2FwLabel[0] = 0;
254*fcf3ce44SJohn Forte 	vpd->sli3FwLabel[0] = 0;
255*fcf3ce44SJohn Forte 	vpd->sli4FwLabel[0] = 0;
256*fcf3ce44SJohn Forte 
257*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_INIT_REV);
258*fcf3ce44SJohn Forte 	emlxs_mb_read_rev(hba, mb, 0);
259*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
260*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
261*fcf3ce44SJohn Forte 		    "Unable to read rev. Mailbox cmd=%x status=%x",
262*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
263*fcf3ce44SJohn Forte 
264*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
265*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
266*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
267*fcf3ce44SJohn Forte 
268*fcf3ce44SJohn Forte 		return (EIO);
269*fcf3ce44SJohn Forte 	}
270*fcf3ce44SJohn Forte 	if (mb->un.varRdRev.rr == 0) {
271*fcf3ce44SJohn Forte 		/* Old firmware */
272*fcf3ce44SJohn Forte 		if (read_rev_reset == 0) {
273*fcf3ce44SJohn Forte 			/* Clean up */
274*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
275*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
276*fcf3ce44SJohn Forte 
277*fcf3ce44SJohn Forte 			read_rev_reset = 1;
278*fcf3ce44SJohn Forte 
279*fcf3ce44SJohn Forte 			goto reset;
280*fcf3ce44SJohn Forte 		} else {
281*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
282*fcf3ce44SJohn Forte 			    "Outdated firmware detected.");
283*fcf3ce44SJohn Forte 		}
284*fcf3ce44SJohn Forte 
285*fcf3ce44SJohn Forte 		vpd->rBit = 0;
286*fcf3ce44SJohn Forte 	} else {
287*fcf3ce44SJohn Forte 		if (mb->un.varRdRev.un.b.ProgType != FUNC_FIRMWARE) {
288*fcf3ce44SJohn Forte 			if (read_rev_reset == 0) {
289*fcf3ce44SJohn Forte 				/* Clean up */
290*fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_MBOX,
291*fcf3ce44SJohn Forte 				    (uint8_t *)mb);
292*fcf3ce44SJohn Forte 				(void) emlxs_mem_free_buffer(hba);
293*fcf3ce44SJohn Forte 
294*fcf3ce44SJohn Forte 				read_rev_reset = 1;
295*fcf3ce44SJohn Forte 
296*fcf3ce44SJohn Forte 				goto reset;
297*fcf3ce44SJohn Forte 			} else {
298*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
299*fcf3ce44SJohn Forte 				    "Non-operational firmware detected. "
300*fcf3ce44SJohn Forte 				    "type=%x",
301*fcf3ce44SJohn Forte 				    mb->un.varRdRev.un.b.ProgType);
302*fcf3ce44SJohn Forte 			}
303*fcf3ce44SJohn Forte 		}
304*fcf3ce44SJohn Forte 		vpd->rBit = 1;
305*fcf3ce44SJohn Forte 		vpd->sli1FwRev = mb->un.varRdRev.sliFwRev1;
306*fcf3ce44SJohn Forte 		bcopy((char *)mb->un.varRdRev.sliFwName1,
307*fcf3ce44SJohn Forte 		    vpd->sli1FwLabel, 16);
308*fcf3ce44SJohn Forte 		vpd->sli2FwRev = mb->un.varRdRev.sliFwRev2;
309*fcf3ce44SJohn Forte 		bcopy((char *)mb->un.varRdRev.sliFwName2,
310*fcf3ce44SJohn Forte 		    vpd->sli2FwLabel, 16);
311*fcf3ce44SJohn Forte 
312*fcf3ce44SJohn Forte 		/* Lets try to read the SLI3 version */
313*fcf3ce44SJohn Forte 		/* Setup and issue mailbox READ REV(v3) command */
314*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_INIT_REV);
315*fcf3ce44SJohn Forte 		emlxs_mb_read_rev(hba, mb, 1);
316*fcf3ce44SJohn Forte 
317*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
318*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
319*fcf3ce44SJohn Forte 			    "Unable to read rev (v3). Mailbox cmd=%x status=%x",
320*fcf3ce44SJohn Forte 			    mb->mbxCommand, mb->mbxStatus);
321*fcf3ce44SJohn Forte 
322*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
323*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
324*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
325*fcf3ce44SJohn Forte 
326*fcf3ce44SJohn Forte 			return (EIO);
327*fcf3ce44SJohn Forte 		}
328*fcf3ce44SJohn Forte 		if (mb->un.varRdRev.rf3) {
329*fcf3ce44SJohn Forte 			/*
330*fcf3ce44SJohn Forte 			 * vpd->sli2FwRev = mb->un.varRdRev.sliFwRev1;  Not
331*fcf3ce44SJohn Forte 			 * needed
332*fcf3ce44SJohn Forte 			 */
333*fcf3ce44SJohn Forte 			vpd->sli3FwRev = mb->un.varRdRev.sliFwRev2;
334*fcf3ce44SJohn Forte 			bcopy((char *)mb->un.varRdRev.sliFwName2,
335*fcf3ce44SJohn Forte 			    vpd->sli3FwLabel, 16);
336*fcf3ce44SJohn Forte 		}
337*fcf3ce44SJohn Forte 	}
338*fcf3ce44SJohn Forte 
339*fcf3ce44SJohn Forte 	/* Check sli mode against available firmware levels */
340*fcf3ce44SJohn Forte 	if ((sli_mode == 4) && (vpd->sli4FwRev == 0)) {
341*fcf3ce44SJohn Forte 		if (vpd->sli3FwRev) {
342*fcf3ce44SJohn Forte 			sli_mode = 3;
343*fcf3ce44SJohn Forte 		} else if (vpd->sli2FwRev) {
344*fcf3ce44SJohn Forte 			sli_mode = 2;
345*fcf3ce44SJohn Forte 		} else {
346*fcf3ce44SJohn Forte 			sli_mode = 0;
347*fcf3ce44SJohn Forte 		}
348*fcf3ce44SJohn Forte 	} else if ((sli_mode == 3) && (vpd->sli3FwRev == 0)) {
349*fcf3ce44SJohn Forte 		if (vpd->sli4FwRev) {
350*fcf3ce44SJohn Forte 			sli_mode = 4;
351*fcf3ce44SJohn Forte 		} else if (vpd->sli2FwRev) {
352*fcf3ce44SJohn Forte 			sli_mode = 2;
353*fcf3ce44SJohn Forte 		} else {
354*fcf3ce44SJohn Forte 			sli_mode = 0;
355*fcf3ce44SJohn Forte 		}
356*fcf3ce44SJohn Forte 	} else if ((sli_mode == 2) && (vpd->sli2FwRev == 0)) {
357*fcf3ce44SJohn Forte 		if (vpd->sli4FwRev) {
358*fcf3ce44SJohn Forte 			sli_mode = 4;
359*fcf3ce44SJohn Forte 		} else if (vpd->sli3FwRev) {
360*fcf3ce44SJohn Forte 			sli_mode = 3;
361*fcf3ce44SJohn Forte 		} else {
362*fcf3ce44SJohn Forte 			sli_mode = 0;
363*fcf3ce44SJohn Forte 		}
364*fcf3ce44SJohn Forte 	}
365*fcf3ce44SJohn Forte 	if (sli_mode == 0) {
366*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
367*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
368*fcf3ce44SJohn Forte 		    "Firmware not available. sli-mode=%d",
369*fcf3ce44SJohn Forte 		    cfg[CFG_SLI_MODE].current);
370*fcf3ce44SJohn Forte #else
371*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
372*fcf3ce44SJohn Forte 		    "Firmware not available. sli-mode=2");
373*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
374*fcf3ce44SJohn Forte 
375*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
376*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
377*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
378*fcf3ce44SJohn Forte 
379*fcf3ce44SJohn Forte 		return (EIO);
380*fcf3ce44SJohn Forte 	}
381*fcf3ce44SJohn Forte 	/* Save information as VPD data */
382*fcf3ce44SJohn Forte 	vpd->postKernRev = mb->un.varRdRev.postKernRev;
383*fcf3ce44SJohn Forte 	vpd->opFwRev = mb->un.varRdRev.opFwRev;
384*fcf3ce44SJohn Forte 	bcopy((char *)mb->un.varRdRev.opFwName, vpd->opFwLabel, 16);
385*fcf3ce44SJohn Forte 	vpd->biuRev = mb->un.varRdRev.biuRev;
386*fcf3ce44SJohn Forte 	vpd->smRev = mb->un.varRdRev.smRev;
387*fcf3ce44SJohn Forte 	vpd->smFwRev = mb->un.varRdRev.un.smFwRev;
388*fcf3ce44SJohn Forte 	vpd->endecRev = mb->un.varRdRev.endecRev;
389*fcf3ce44SJohn Forte 	vpd->fcphHigh = mb->un.varRdRev.fcphHigh;
390*fcf3ce44SJohn Forte 	vpd->fcphLow = mb->un.varRdRev.fcphLow;
391*fcf3ce44SJohn Forte 	vpd->feaLevelHigh = mb->un.varRdRev.feaLevelHigh;
392*fcf3ce44SJohn Forte 	vpd->feaLevelLow = mb->un.varRdRev.feaLevelLow;
393*fcf3ce44SJohn Forte 
394*fcf3ce44SJohn Forte 	/* Decode FW names */
395*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->postKernRev, vpd->postKernName);
396*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->opFwRev, vpd->opFwName);
397*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->sli1FwRev, vpd->sli1FwName);
398*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->sli2FwRev, vpd->sli2FwName);
399*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->sli3FwRev, vpd->sli3FwName);
400*fcf3ce44SJohn Forte 	emlxs_decode_version(vpd->sli4FwRev, vpd->sli4FwName);
401*fcf3ce44SJohn Forte 
402*fcf3ce44SJohn Forte 	/* Decode FW labels */
403*fcf3ce44SJohn Forte 	emlxs_decode_label(vpd->opFwLabel, vpd->opFwLabel);
404*fcf3ce44SJohn Forte 	emlxs_decode_label(vpd->sli1FwLabel, vpd->sli1FwLabel);
405*fcf3ce44SJohn Forte 	emlxs_decode_label(vpd->sli2FwLabel, vpd->sli2FwLabel);
406*fcf3ce44SJohn Forte 	emlxs_decode_label(vpd->sli3FwLabel, vpd->sli3FwLabel);
407*fcf3ce44SJohn Forte 	emlxs_decode_label(vpd->sli4FwLabel, vpd->sli4FwLabel);
408*fcf3ce44SJohn Forte 
409*fcf3ce44SJohn Forte 	key = emlxs_get_key(hba, mb);
410*fcf3ce44SJohn Forte 
411*fcf3ce44SJohn Forte 	/* Get adapter VPD information */
412*fcf3ce44SJohn Forte 	offset = 0;
413*fcf3ce44SJohn Forte 	bzero(vpd_data, sizeof (vpd_data));
414*fcf3ce44SJohn Forte 	vpd->port_index = (uint32_t)-1;
415*fcf3ce44SJohn Forte 
416*fcf3ce44SJohn Forte 	while (offset < DMP_VPD_SIZE) {
417*fcf3ce44SJohn Forte 		emlxs_mb_dump_vpd(hba, mb, offset);
418*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
419*fcf3ce44SJohn Forte 			/*
420*fcf3ce44SJohn Forte 			 * Let it go through even if failed.*
421*fcf3ce44SJohn Forte 			 */
422*fcf3ce44SJohn Forte 			/*
423*fcf3ce44SJohn Forte 			 * Not all adapter's have VPD info and thus will fail
424*fcf3ce44SJohn Forte 			 * here
425*fcf3ce44SJohn Forte 			 */
426*fcf3ce44SJohn Forte 			/* This is not a problem */
427*fcf3ce44SJohn Forte 
428*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
429*fcf3ce44SJohn Forte 			    "No VPD found. offset=%x status=%x",
430*fcf3ce44SJohn Forte 			    offset, mb->mbxStatus);
431*fcf3ce44SJohn Forte 			break;
432*fcf3ce44SJohn Forte 		} else {
433*fcf3ce44SJohn Forte 			if (mb->un.varDmp.ra == 1) {
434*fcf3ce44SJohn Forte 				uint32_t *lp1, *lp2;
435*fcf3ce44SJohn Forte 				uint32_t bsize;
436*fcf3ce44SJohn Forte 				uint32_t wsize;
437*fcf3ce44SJohn Forte 
438*fcf3ce44SJohn Forte 				/*
439*fcf3ce44SJohn Forte 				 * mb->un.varDmp.word_cnt is actually byte
440*fcf3ce44SJohn Forte 				 * count for the dump reply
441*fcf3ce44SJohn Forte 				 */
442*fcf3ce44SJohn Forte 				bsize = mb->un.varDmp.word_cnt;
443*fcf3ce44SJohn Forte 
444*fcf3ce44SJohn Forte 				/* Stop if no data was received */
445*fcf3ce44SJohn Forte 				if (bsize == 0) {
446*fcf3ce44SJohn Forte 					break;
447*fcf3ce44SJohn Forte 				}
448*fcf3ce44SJohn Forte 				/* Check limit on byte size */
449*fcf3ce44SJohn Forte 				bsize = (bsize > (sizeof (vpd_data) - offset)) ?
450*fcf3ce44SJohn Forte 				    (sizeof (vpd_data) - offset) : bsize;
451*fcf3ce44SJohn Forte 
452*fcf3ce44SJohn Forte 				/*
453*fcf3ce44SJohn Forte 				 * Convert size from bytes to words with
454*fcf3ce44SJohn Forte 				 * minimum of 1 word
455*fcf3ce44SJohn Forte 				 */
456*fcf3ce44SJohn Forte 				wsize = (bsize > 4) ? (bsize >> 2) : 1;
457*fcf3ce44SJohn Forte 
458*fcf3ce44SJohn Forte 				/*
459*fcf3ce44SJohn Forte 				 * Transfer data into vpd_data buffer one
460*fcf3ce44SJohn Forte 				 * word at a time
461*fcf3ce44SJohn Forte 				 */
462*fcf3ce44SJohn Forte 				lp1 = (uint32_t *)&mb->un.varDmp.resp_offset;
463*fcf3ce44SJohn Forte 				lp2 = (uint32_t *)&vpd_data[offset];
464*fcf3ce44SJohn Forte 
465*fcf3ce44SJohn Forte 				for (i = 0; i < wsize; i++) {
466*fcf3ce44SJohn Forte 					status = *lp1++;
467*fcf3ce44SJohn Forte 					*lp2++ = SWAP_LONG(status);
468*fcf3ce44SJohn Forte 				}
469*fcf3ce44SJohn Forte 
470*fcf3ce44SJohn Forte 				/* Increment total byte count saved */
471*fcf3ce44SJohn Forte 				offset += (wsize << 2);
472*fcf3ce44SJohn Forte 
473*fcf3ce44SJohn Forte 				/*
474*fcf3ce44SJohn Forte 				 * Stop if less than a full transfer was
475*fcf3ce44SJohn Forte 				 * received
476*fcf3ce44SJohn Forte 				 */
477*fcf3ce44SJohn Forte 				if (wsize < DMP_VPD_DUMP_WCOUNT) {
478*fcf3ce44SJohn Forte 					break;
479*fcf3ce44SJohn Forte 				}
480*fcf3ce44SJohn Forte 			} else {
481*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
482*fcf3ce44SJohn Forte 				    "No VPD acknowledgment. offset=%x", offset);
483*fcf3ce44SJohn Forte 				break;
484*fcf3ce44SJohn Forte 			}
485*fcf3ce44SJohn Forte 		}
486*fcf3ce44SJohn Forte 
487*fcf3ce44SJohn Forte 	}
488*fcf3ce44SJohn Forte 
489*fcf3ce44SJohn Forte 	if (vpd_data[0]) {
490*fcf3ce44SJohn Forte 
491*fcf3ce44SJohn Forte 		(void) emlxs_parse_vpd(hba, (uint8_t *)vpd_data, offset);
492*fcf3ce44SJohn Forte 
493*fcf3ce44SJohn Forte 		/*
494*fcf3ce44SJohn Forte 		 * Some adapter models require the vpd data to identify the
495*fcf3ce44SJohn Forte 		 * exact model
496*fcf3ce44SJohn Forte 		 */
497*fcf3ce44SJohn Forte 
498*fcf3ce44SJohn Forte 		/*
499*fcf3ce44SJohn Forte 		 * Check if vpd->part_num is now defined and the LP8000
500*fcf3ce44SJohn Forte 		 * adapter (This is a special case)
501*fcf3ce44SJohn Forte 		 */
502*fcf3ce44SJohn Forte 		/* We need to look for LP8000DC */
503*fcf3ce44SJohn Forte 		if ((hba->model_info.device_id == PCI_DEVICE_ID_LP8000) &&
504*fcf3ce44SJohn Forte 		    (vpd->part_num[0] != 0)) {
505*fcf3ce44SJohn Forte 			if (strncmp(vpd->part_num, "LP8000DC", 8) == 0) {
506*fcf3ce44SJohn Forte 				/* LP8000DC */
507*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
508*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP8000DC) {
509*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
510*fcf3ce44SJohn Forte 						    &hba->model_info,
511*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
512*fcf3ce44SJohn Forte 						break;
513*fcf3ce44SJohn Forte 					}
514*fcf3ce44SJohn Forte 				}
515*fcf3ce44SJohn Forte 			} else if (hba->model_info.id != LP8000) {
516*fcf3ce44SJohn Forte 				/* LP8000 */
517*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
518*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP8000) {
519*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
520*fcf3ce44SJohn Forte 						    &hba->model_info,
521*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
522*fcf3ce44SJohn Forte 						break;
523*fcf3ce44SJohn Forte 					}
524*fcf3ce44SJohn Forte 				}
525*fcf3ce44SJohn Forte 			}
526*fcf3ce44SJohn Forte 		}
527*fcf3ce44SJohn Forte 		/* PCI_DEVICE_ID_LP8000 */
528*fcf3ce44SJohn Forte 		/*
529*fcf3ce44SJohn Forte 		 * Check if vpd->part_num is now defined and the LP9002L
530*fcf3ce44SJohn Forte 		 * adapter (This is a special case)
531*fcf3ce44SJohn Forte 		 */
532*fcf3ce44SJohn Forte 		/*
533*fcf3ce44SJohn Forte 		 * We need to look for LP9002C, LP9002DC, and the LP9402DC
534*fcf3ce44SJohn Forte 		 * adapters
535*fcf3ce44SJohn Forte 		 */
536*fcf3ce44SJohn Forte 		else if ((hba->model_info.device_id == PCI_DEVICE_ID_LP9002L) &&
537*fcf3ce44SJohn Forte 		    (vpd->part_num[0] != 0)) {
538*fcf3ce44SJohn Forte 			if (strncmp(vpd->part_num, "LP9002C", 7) == 0) {
539*fcf3ce44SJohn Forte 				/* LP9002C */
540*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
541*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9002C) {
542*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
543*fcf3ce44SJohn Forte 						    &hba->model_info,
544*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
545*fcf3ce44SJohn Forte 						break;
546*fcf3ce44SJohn Forte 					}
547*fcf3ce44SJohn Forte 				}
548*fcf3ce44SJohn Forte 			} else if (strncmp(vpd->part_num, "LP9002DC", 8) == 0) {
549*fcf3ce44SJohn Forte 				/* LP9002DC */
550*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
551*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9002DC) {
552*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
553*fcf3ce44SJohn Forte 						    &hba->model_info,
554*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
555*fcf3ce44SJohn Forte 						break;
556*fcf3ce44SJohn Forte 					}
557*fcf3ce44SJohn Forte 				}
558*fcf3ce44SJohn Forte 			} else if (strncmp(vpd->part_num, "LP9402DC", 8) == 0) {
559*fcf3ce44SJohn Forte 				/* LP9402DC */
560*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
561*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9402DC) {
562*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
563*fcf3ce44SJohn Forte 						    &hba->model_info,
564*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
565*fcf3ce44SJohn Forte 						break;
566*fcf3ce44SJohn Forte 					}
567*fcf3ce44SJohn Forte 				}
568*fcf3ce44SJohn Forte 			} else if (hba->model_info.id != LP9002L) {
569*fcf3ce44SJohn Forte 				/* LP9002 */
570*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
571*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP9002L) {
572*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
573*fcf3ce44SJohn Forte 						    &hba->model_info,
574*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
575*fcf3ce44SJohn Forte 						break;
576*fcf3ce44SJohn Forte 					}
577*fcf3ce44SJohn Forte 				}
578*fcf3ce44SJohn Forte 			}
579*fcf3ce44SJohn Forte 		}
580*fcf3ce44SJohn Forte 		/* PCI_DEVICE_ID_LP9002 */
581*fcf3ce44SJohn Forte 		/*
582*fcf3ce44SJohn Forte 		 * We need the vpd->part_num to decern between the LP10000DC
583*fcf3ce44SJohn Forte 		 * and LP10000ExDC
584*fcf3ce44SJohn Forte 		 */
585*fcf3ce44SJohn Forte 		else if ((hba->model_info.device_id == PCI_DEVICE_ID_LP10000) &&
586*fcf3ce44SJohn Forte 		    (vpd->part_num[0] != 0)) {
587*fcf3ce44SJohn Forte 			if (strncmp(vpd->part_num, "LP10000DC", 9) == 0) {
588*fcf3ce44SJohn Forte 				/* LP10000DC */
589*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
590*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id ==
591*fcf3ce44SJohn Forte 					    LP10000DC) {
592*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
593*fcf3ce44SJohn Forte 						    &hba->model_info,
594*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
595*fcf3ce44SJohn Forte 						break;
596*fcf3ce44SJohn Forte 					}
597*fcf3ce44SJohn Forte 				}
598*fcf3ce44SJohn Forte 			} else if (strncmp(vpd->part_num, "LP10000ExDC", 11)
599*fcf3ce44SJohn Forte 			    == 0) {
600*fcf3ce44SJohn Forte 				/* LP10000ExDC */
601*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
602*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id ==
603*fcf3ce44SJohn Forte 					    LP10000ExDC) {
604*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
605*fcf3ce44SJohn Forte 						    &hba->model_info,
606*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
607*fcf3ce44SJohn Forte 						break;
608*fcf3ce44SJohn Forte 					}
609*fcf3ce44SJohn Forte 				}
610*fcf3ce44SJohn Forte 			} else if (hba->model_info.id != LP10000) {
611*fcf3ce44SJohn Forte 				/* LP10000 */
612*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
613*fcf3ce44SJohn Forte 					if (emlxs_pci_model[i].id == LP10000) {
614*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
615*fcf3ce44SJohn Forte 						    &hba->model_info,
616*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
617*fcf3ce44SJohn Forte 						break;
618*fcf3ce44SJohn Forte 					}
619*fcf3ce44SJohn Forte 				}
620*fcf3ce44SJohn Forte 			}
621*fcf3ce44SJohn Forte 		}	/* PCI_DEVICE_ID_LP10000 */
622*fcf3ce44SJohn Forte 		/* Replace the default model description with vpd data */
623*fcf3ce44SJohn Forte 		if (vpd->model_desc[0] != 0) {
624*fcf3ce44SJohn Forte 			(void) strcpy(hba->model_info.model_desc,
625*fcf3ce44SJohn Forte 			    vpd->model_desc);
626*fcf3ce44SJohn Forte 		}
627*fcf3ce44SJohn Forte 		/* Replace the default model with vpd data */
628*fcf3ce44SJohn Forte 		if (vpd->model[0] != 0) {
629*fcf3ce44SJohn Forte 			(void) strcpy(hba->model_info.model, vpd->model);
630*fcf3ce44SJohn Forte 		}
631*fcf3ce44SJohn Forte 		/* Replace the default program types with vpd data */
632*fcf3ce44SJohn Forte 		if (vpd->prog_types[0] != 0) {
633*fcf3ce44SJohn Forte 			emlxs_parse_prog_types(hba, vpd->prog_types);
634*fcf3ce44SJohn Forte 		}
635*fcf3ce44SJohn Forte 	}
636*fcf3ce44SJohn Forte 	/* Since the adapter model may have changed with the vpd data */
637*fcf3ce44SJohn Forte 	/* lets double check if adapter is not supported */
638*fcf3ce44SJohn Forte 	if (hba->model_info.flags & EMLXS_NOT_SUPPORTED) {
639*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
640*fcf3ce44SJohn Forte 		    "Unsupported adapter found.  Id:%d  Device id:0x%x "
641*fcf3ce44SJohn Forte 		    "SSDID:0x%x  Model:%s", hba->model_info.id,
642*fcf3ce44SJohn Forte 		    hba->model_info.device_id, hba->model_info.ssdid,
643*fcf3ce44SJohn Forte 		    hba->model_info.model);
644*fcf3ce44SJohn Forte 
645*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
646*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
647*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
648*fcf3ce44SJohn Forte 
649*fcf3ce44SJohn Forte 		return (EIO);
650*fcf3ce44SJohn Forte 	}
651*fcf3ce44SJohn Forte 	/* Read the adapter's wakeup parms */
652*fcf3ce44SJohn Forte 	(void) emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 1);
653*fcf3ce44SJohn Forte 	emlxs_decode_version(hba->wakeup_parms.u0.boot_bios_wd[0],
654*fcf3ce44SJohn Forte 	    vpd->boot_version);
655*fcf3ce44SJohn Forte 
656*fcf3ce44SJohn Forte 	/* Get fcode version property */
657*fcf3ce44SJohn Forte 	emlxs_get_fcode_version(hba);
658*fcf3ce44SJohn Forte 
659*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
660*fcf3ce44SJohn Forte 	    "Firmware: kern=%08x stub=%08x sli1=%08x",
661*fcf3ce44SJohn Forte 	    vpd->postKernRev, vpd->opFwRev, vpd->sli1FwRev);
662*fcf3ce44SJohn Forte 
663*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
664*fcf3ce44SJohn Forte 	    "Firmware: sli2=%08x sli3=%08x sli4=%08x fl=%x",
665*fcf3ce44SJohn Forte 	    vpd->sli2FwRev, vpd->sli3FwRev, vpd->sli4FwRev, vpd->feaLevelHigh);
666*fcf3ce44SJohn Forte 
667*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
668*fcf3ce44SJohn Forte 	    "BIOS: boot=%s fcode=%s", vpd->boot_version, vpd->fcode_version);
669*fcf3ce44SJohn Forte 
670*fcf3ce44SJohn Forte 	/*
671*fcf3ce44SJohn Forte 	 * If firmware checking is enabled and the adapter model indicates a
672*fcf3ce44SJohn Forte 	 * firmware image,
673*fcf3ce44SJohn Forte 	 */
674*fcf3ce44SJohn Forte 	/* then perform firmware version check */
675*fcf3ce44SJohn Forte 	if (((fw_check == 1) && (hba->model_info.flags & EMLXS_SUN_BRANDED) &&
676*fcf3ce44SJohn Forte 	    hba->model_info.fwid) ||
677*fcf3ce44SJohn Forte 	    ((fw_check == 2) && hba->model_info.fwid)) {
678*fcf3ce44SJohn Forte 		emlxs_image_t *image;
679*fcf3ce44SJohn Forte 
680*fcf3ce44SJohn Forte 		/* Find firmware image indicated by adapter model */
681*fcf3ce44SJohn Forte 		image = NULL;
682*fcf3ce44SJohn Forte 		for (i = 0; i < EMLXS_IMAGE_COUNT; i++) {
683*fcf3ce44SJohn Forte 			if (emlxs_fw_image[i].id == hba->model_info.fwid) {
684*fcf3ce44SJohn Forte 				image = &emlxs_fw_image[i];
685*fcf3ce44SJohn Forte 				break;
686*fcf3ce44SJohn Forte 			}
687*fcf3ce44SJohn Forte 		}
688*fcf3ce44SJohn Forte 
689*fcf3ce44SJohn Forte 		/*
690*fcf3ce44SJohn Forte 		 * If the image was found, then verify current firmware
691*fcf3ce44SJohn Forte 		 * versions of adapter
692*fcf3ce44SJohn Forte 		 */
693*fcf3ce44SJohn Forte 		if (image) {
694*fcf3ce44SJohn Forte 			if ((vpd->postKernRev != image->kern) ||
695*fcf3ce44SJohn Forte 			    (vpd->opFwRev != image->stub) ||
696*fcf3ce44SJohn Forte 			    (vpd->sli1FwRev != image->sli1) ||
697*fcf3ce44SJohn Forte 			    (vpd->sli2FwRev != image->sli2) ||
698*fcf3ce44SJohn Forte 			    (image->sli3 && (vpd->sli3FwRev != image->sli3)) ||
699*fcf3ce44SJohn Forte 			    (image->sli4 && (vpd->sli4FwRev != image->sli4))) {
700*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
701*fcf3ce44SJohn Forte 				    "Firmware update needed. Updating... "
702*fcf3ce44SJohn Forte 				    "(id=%d fw=%d)", hba->model_info.id,
703*fcf3ce44SJohn Forte 				    hba->model_info.fwid);
704*fcf3ce44SJohn Forte 
705*fcf3ce44SJohn Forte 				if (emlxs_fw_download(hba,
706*fcf3ce44SJohn Forte 				    (char *)image->buffer, image->size, 0)) {
707*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
708*fcf3ce44SJohn Forte 					    &emlxs_init_failed_msg,
709*fcf3ce44SJohn Forte 					    "Firmware update failed.");
710*fcf3ce44SJohn Forte 				}
711*fcf3ce44SJohn Forte 				/* Clean up */
712*fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_MBOX,
713*fcf3ce44SJohn Forte 				    (uint8_t *)mb);
714*fcf3ce44SJohn Forte 				(void) emlxs_mem_free_buffer(hba);
715*fcf3ce44SJohn Forte 
716*fcf3ce44SJohn Forte 				fw_check = 0;
717*fcf3ce44SJohn Forte 
718*fcf3ce44SJohn Forte 				goto reset;
719*fcf3ce44SJohn Forte 			}
720*fcf3ce44SJohn Forte 		} else {
721*fcf3ce44SJohn Forte 			/* This should not happen */
722*fcf3ce44SJohn Forte 
723*fcf3ce44SJohn Forte 			/*
724*fcf3ce44SJohn Forte 			 * This means either the adapter database is not
725*fcf3ce44SJohn Forte 			 * correct or a firmware image is missing from the
726*fcf3ce44SJohn Forte 			 * compile
727*fcf3ce44SJohn Forte 			 */
728*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
729*fcf3ce44SJohn Forte 			    "Driver firmware image unavailable. (id=%d fw=%d)",
730*fcf3ce44SJohn Forte 			    hba->model_info.id, hba->model_info.fwid);
731*fcf3ce44SJohn Forte 		}
732*fcf3ce44SJohn Forte 
733*fcf3ce44SJohn Forte 	}
734*fcf3ce44SJohn Forte 	/* Add our interrupt routine to kernel's interrupt chain & enable it */
735*fcf3ce44SJohn Forte 	/*
736*fcf3ce44SJohn Forte 	 * If MSI is enabled this will cause Solaris to program the MSI
737*fcf3ce44SJohn Forte 	 * address
738*fcf3ce44SJohn Forte 	 */
739*fcf3ce44SJohn Forte 	/* and data registers in PCI config space */
740*fcf3ce44SJohn Forte 	if (EMLXS_INTR_ADD(hba) != DDI_SUCCESS) {
741*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
742*fcf3ce44SJohn Forte 		    "Unable to add interrupt(s).");
743*fcf3ce44SJohn Forte 
744*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
745*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
746*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
747*fcf3ce44SJohn Forte 
748*fcf3ce44SJohn Forte 		return (EIO);
749*fcf3ce44SJohn Forte 	}
750*fcf3ce44SJohn Forte 	/*
751*fcf3ce44SJohn Forte 	 * Initialize cmd/rsp ring pointers
752*fcf3ce44SJohn Forte 	 */
753*fcf3ce44SJohn Forte 	for (i = 0; i < (uint32_t)hba->ring_count; i++) {
754*fcf3ce44SJohn Forte 		rp = &hba->ring[i];
755*fcf3ce44SJohn Forte 
756*fcf3ce44SJohn Forte 		rp->hba = hba;
757*fcf3ce44SJohn Forte 		rp->ringno = (uint8_t)i;
758*fcf3ce44SJohn Forte 
759*fcf3ce44SJohn Forte 		rp->fc_iocbhd = 0;
760*fcf3ce44SJohn Forte 		rp->fc_iocbtl = 0;
761*fcf3ce44SJohn Forte 		rp->fc_cmdidx = 0;
762*fcf3ce44SJohn Forte 		rp->fc_rspidx = 0;
763*fcf3ce44SJohn Forte 		/* Used for pkt io */
764*fcf3ce44SJohn Forte 		rp->fc_iotag = 1;
765*fcf3ce44SJohn Forte 		/* Used for abort or close XRI iotags */
766*fcf3ce44SJohn Forte 		rp->fc_abort_iotag = rp->max_iotag;
767*fcf3ce44SJohn Forte 
768*fcf3ce44SJohn Forte 	}
769*fcf3ce44SJohn Forte 
770*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_INIT_CFGPORT);
771*fcf3ce44SJohn Forte 	(void) emlxs_mb_config_port(hba, mb, sli_mode, key);
772*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
773*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
774*fcf3ce44SJohn Forte 		    "Unable to configure port. Mailbox cmd=%x status=%x "
775*fcf3ce44SJohn Forte 		    "slimode=%d key=%x", mb->mbxCommand, mb->mbxStatus,
776*fcf3ce44SJohn Forte 		    sli_mode, key);
777*fcf3ce44SJohn Forte 
778*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
779*fcf3ce44SJohn Forte 		/* Try to fall back to SLI2 if possible */
780*fcf3ce44SJohn Forte 		if (sli_mode >= 3) {
781*fcf3ce44SJohn Forte 			sli_mode = 2;
782*fcf3ce44SJohn Forte 
783*fcf3ce44SJohn Forte 			/* Clean up */
784*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
785*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
786*fcf3ce44SJohn Forte 
787*fcf3ce44SJohn Forte 			fw_check = 0;
788*fcf3ce44SJohn Forte 
789*fcf3ce44SJohn Forte 			goto reset;
790*fcf3ce44SJohn Forte 		}
791*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
792*fcf3ce44SJohn Forte 
793*fcf3ce44SJohn Forte 		hba->flag &= ~FC_SLIM2_MODE;
794*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
795*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
796*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
797*fcf3ce44SJohn Forte 
798*fcf3ce44SJohn Forte 		return (EIO);
799*fcf3ce44SJohn Forte 	}
800*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
801*fcf3ce44SJohn Forte 	/* Check if SLI3 mode was achieved */
802*fcf3ce44SJohn Forte 	if (mb->un.varCfgPort.rMA && (mb->un.varCfgPort.sli_mode == 3)) {
803*fcf3ce44SJohn Forte 		hba->sli_mode = 3;
804*fcf3ce44SJohn Forte 
805*fcf3ce44SJohn Forte #ifdef NPIV_SUPPORT
806*fcf3ce44SJohn Forte 		if (mb->un.varCfgPort.vpi_max > 1) {
807*fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_ENABLED;
808*fcf3ce44SJohn Forte 
809*fcf3ce44SJohn Forte 			if (hba->model_info.chip >= EMLXS_SATURN_CHIP) {
810*fcf3ce44SJohn Forte 				hba->vpi_max = min(mb->un.varCfgPort.vpi_max,
811*fcf3ce44SJohn Forte 				    MAX_VPORTS - 1);
812*fcf3ce44SJohn Forte 			} else {
813*fcf3ce44SJohn Forte 				hba->vpi_max = min(mb->un.varCfgPort.vpi_max,
814*fcf3ce44SJohn Forte 				    MAX_VPORTS_LIMITED - 1);
815*fcf3ce44SJohn Forte 			}
816*fcf3ce44SJohn Forte 		}
817*fcf3ce44SJohn Forte #endif	/* NPIV_SUPPORT */
818*fcf3ce44SJohn Forte 
819*fcf3ce44SJohn Forte 		if (mb->un.varCfgPort.gerbm && mb->un.varCfgPort.max_hbq) {
820*fcf3ce44SJohn Forte 			hba->flag |= FC_HBQ_ENABLED;
821*fcf3ce44SJohn Forte 		}
822*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
823*fcf3ce44SJohn Forte 		    "SLI3 mode: flag=%x vpi_max=%d", hba->flag, hba->vpi_max);
824*fcf3ce44SJohn Forte 	} else {
825*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
826*fcf3ce44SJohn Forte 		    "SLI2 mode: flag=%x", hba->flag);
827*fcf3ce44SJohn Forte 	}
828*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
829*fcf3ce44SJohn Forte 
830*fcf3ce44SJohn Forte 	/* Get and save the current firmware version (based on sli_mode) */
831*fcf3ce44SJohn Forte 	emlxs_decode_firmware_rev(hba, vpd);
832*fcf3ce44SJohn Forte 
833*fcf3ce44SJohn Forte 	emlxs_pcix_mxr_update(hba, 0);
834*fcf3ce44SJohn Forte 
835*fcf3ce44SJohn Forte 	/*
836*fcf3ce44SJohn Forte 	 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers
837*fcf3ce44SJohn Forte 	 */
838*fcf3ce44SJohn Forte 	mp = 0;
839*fcf3ce44SJohn Forte 	mp1 = 0;
840*fcf3ce44SJohn Forte 	if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0) ||
841*fcf3ce44SJohn Forte 	    ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0)) {
842*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
843*fcf3ce44SJohn Forte 		    "Unable to allocate diag buffers.");
844*fcf3ce44SJohn Forte 
845*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
846*fcf3ce44SJohn Forte 
847*fcf3ce44SJohn Forte 		if (mp) {
848*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
849*fcf3ce44SJohn Forte 		}
850*fcf3ce44SJohn Forte 		if (mp1) {
851*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1);
852*fcf3ce44SJohn Forte 		}
853*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
854*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
855*fcf3ce44SJohn Forte 
856*fcf3ce44SJohn Forte 		return (ENOMEM);
857*fcf3ce44SJohn Forte 	}
858*fcf3ce44SJohn Forte 	bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt,
859*fcf3ce44SJohn Forte 	    MEM_ELSBUF_SIZE);
860*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(mp->dma_handle, 0, MEM_ELSBUF_SIZE,
861*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORDEV);
862*fcf3ce44SJohn Forte 
863*fcf3ce44SJohn Forte 	bzero(mp1->virt, MEM_ELSBUF_SIZE);
864*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
865*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORDEV);
866*fcf3ce44SJohn Forte 
867*fcf3ce44SJohn Forte 	(void) emlxs_mb_run_biu_diag(hba, mb, mp->phys, mp1->phys);
868*fcf3ce44SJohn Forte 
869*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
870*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
871*fcf3ce44SJohn Forte 		    "Unable to run BIU diag.  Mailbox cmd=%x status=%x",
872*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
873*fcf3ce44SJohn Forte 
874*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
875*fcf3ce44SJohn Forte 
876*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
877*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1);
878*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
879*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
880*fcf3ce44SJohn Forte 
881*fcf3ce44SJohn Forte 		return (EIO);
882*fcf3ce44SJohn Forte 	}
883*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
884*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
885*fcf3ce44SJohn Forte 
886*fcf3ce44SJohn Forte 	outptr = mp->virt;
887*fcf3ce44SJohn Forte 	inptr = mp1->virt;
888*fcf3ce44SJohn Forte 
889*fcf3ce44SJohn Forte 	for (i = 0; i < MEM_ELSBUF_SIZE; i++) {
890*fcf3ce44SJohn Forte 		if (*outptr++ != *inptr++) {
891*fcf3ce44SJohn Forte 			outptr--;
892*fcf3ce44SJohn Forte 			inptr--;
893*fcf3ce44SJohn Forte 
894*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
895*fcf3ce44SJohn Forte 			    "BIU diagnostic failed. offset %x value %x "
896*fcf3ce44SJohn Forte 			    "should be %x.", i, (uint32_t)*inptr,
897*fcf3ce44SJohn Forte 			    (uint32_t)*outptr);
898*fcf3ce44SJohn Forte 
899*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
900*fcf3ce44SJohn Forte 
901*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
902*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1);
903*fcf3ce44SJohn Forte 
904*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
905*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
906*fcf3ce44SJohn Forte 
907*fcf3ce44SJohn Forte 			return (EIO);
908*fcf3ce44SJohn Forte 		}
909*fcf3ce44SJohn Forte 	}
910*fcf3ce44SJohn Forte 
911*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
912*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1);
913*fcf3ce44SJohn Forte 
914*fcf3ce44SJohn Forte 	/*
915*fcf3ce44SJohn Forte 	 * Setup and issue mailbox CONFIGURE RING command
916*fcf3ce44SJohn Forte 	 */
917*fcf3ce44SJohn Forte 	for (i = 0; i < (uint32_t)hba->ring_count; i++) {
918*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_INIT_CFGRING);
919*fcf3ce44SJohn Forte 		emlxs_mb_config_ring(hba, i, mb);
920*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
921*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
922*fcf3ce44SJohn Forte 			    "Unable to configure ring. Mailbox cmd=%x "
923*fcf3ce44SJohn Forte 			    "status=%x", mb->mbxCommand, mb->mbxStatus);
924*fcf3ce44SJohn Forte 
925*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
926*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
927*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
928*fcf3ce44SJohn Forte 
929*fcf3ce44SJohn Forte 			return (EIO);
930*fcf3ce44SJohn Forte 		}
931*fcf3ce44SJohn Forte 	}
932*fcf3ce44SJohn Forte 
933*fcf3ce44SJohn Forte 	/*
934*fcf3ce44SJohn Forte 	 * Setup link timers
935*fcf3ce44SJohn Forte 	 */
936*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_INIT_INITLINK);
937*fcf3ce44SJohn Forte 	emlxs_mb_config_link(hba, mb);
938*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
939*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
940*fcf3ce44SJohn Forte 		    "Unable to configure link. Mailbox cmd=%x status=%x",
941*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
942*fcf3ce44SJohn Forte 
943*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
944*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
945*fcf3ce44SJohn Forte 		emlxs_ffcleanup(hba);
946*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
947*fcf3ce44SJohn Forte 
948*fcf3ce44SJohn Forte 		return (EIO);
949*fcf3ce44SJohn Forte 	}
950*fcf3ce44SJohn Forte #ifdef MAX_RRDY_PATCH
951*fcf3ce44SJohn Forte 	/* Set MAX_RRDY if one is provided */
952*fcf3ce44SJohn Forte 	if (cfg[CFG_MAX_RRDY].current) {
953*fcf3ce44SJohn Forte 		emlxs_mb_set_var(hba, (MAILBOX *) mb, 0x00060412,
954*fcf3ce44SJohn Forte 		    cfg[CFG_MAX_RRDY].current);
955*fcf3ce44SJohn Forte 
956*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
957*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
958*fcf3ce44SJohn Forte 			    "MAX_RRDY: Unable to set.  status=%x value=%d",
959*fcf3ce44SJohn Forte 			    mb->mbxStatus, cfg[CFG_MAX_RRDY].current);
960*fcf3ce44SJohn Forte 		} else {
961*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
962*fcf3ce44SJohn Forte 			    "MAX_RRDY: %d", cfg[CFG_MAX_RRDY].current);
963*fcf3ce44SJohn Forte 		}
964*fcf3ce44SJohn Forte 	}
965*fcf3ce44SJohn Forte #endif	/* MAX_RRDY_PATCH */
966*fcf3ce44SJohn Forte 
967*fcf3ce44SJohn Forte 	/*
968*fcf3ce44SJohn Forte 	 * We need to get login parameters for NID
969*fcf3ce44SJohn Forte 	 */
970*fcf3ce44SJohn Forte 	(void) emlxs_mb_read_sparam(hba, mb);
971*fcf3ce44SJohn Forte 	mp = (MATCHMAP *) (((MAILBOXQ *)mb)->bp);
972*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
973*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
974*fcf3ce44SJohn Forte 		    "Unable to read parameters. Mailbox cmd=%x status=%x",
975*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
976*fcf3ce44SJohn Forte 
977*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
978*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
979*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
980*fcf3ce44SJohn Forte 		emlxs_ffcleanup(hba);
981*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
982*fcf3ce44SJohn Forte 
983*fcf3ce44SJohn Forte 		return (EIO);
984*fcf3ce44SJohn Forte 	}
985*fcf3ce44SJohn Forte 	/* Free the buffer since we were polling */
986*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
987*fcf3ce44SJohn Forte 
988*fcf3ce44SJohn Forte 	/* If no serial number in VPD data, then use the WWPN */
989*fcf3ce44SJohn Forte 	if (vpd->serial_num[0] == 0) {
990*fcf3ce44SJohn Forte 		outptr = (uint8_t *)&hba->wwpn.IEEE[0];
991*fcf3ce44SJohn Forte 		for (i = 0; i < 12; i++) {
992*fcf3ce44SJohn Forte 			status = *outptr++;
993*fcf3ce44SJohn Forte 			j = ((status & 0xf0) >> 4);
994*fcf3ce44SJohn Forte 			if (j <= 9) {
995*fcf3ce44SJohn Forte 				vpd->serial_num[i] =
996*fcf3ce44SJohn Forte 				    (char)((uint8_t)'0' + (uint8_t)j);
997*fcf3ce44SJohn Forte 			} else {
998*fcf3ce44SJohn Forte 				vpd->serial_num[i] =
999*fcf3ce44SJohn Forte 				    (char)((uint8_t)'A' + (uint8_t)(j - 10));
1000*fcf3ce44SJohn Forte 			}
1001*fcf3ce44SJohn Forte 
1002*fcf3ce44SJohn Forte 			i++;
1003*fcf3ce44SJohn Forte 			j = (status & 0xf);
1004*fcf3ce44SJohn Forte 			if (j <= 9) {
1005*fcf3ce44SJohn Forte 				vpd->serial_num[i] =
1006*fcf3ce44SJohn Forte 				    (char)((uint8_t)'0' + (uint8_t)j);
1007*fcf3ce44SJohn Forte 			} else {
1008*fcf3ce44SJohn Forte 				vpd->serial_num[i] =
1009*fcf3ce44SJohn Forte 				    (char)((uint8_t)'A' + (uint8_t)(j - 10));
1010*fcf3ce44SJohn Forte 			}
1011*fcf3ce44SJohn Forte 		}
1012*fcf3ce44SJohn Forte 
1013*fcf3ce44SJohn Forte 		/* Set port number and port index to zero */
1014*fcf3ce44SJohn Forte 		/*
1015*fcf3ce44SJohn Forte 		 * The WWN's are unique to each port and therefore port_num
1016*fcf3ce44SJohn Forte 		 * must equal zero
1017*fcf3ce44SJohn Forte 		 */
1018*fcf3ce44SJohn Forte 		/*
1019*fcf3ce44SJohn Forte 		 * This effects the hba_fru_details structure in
1020*fcf3ce44SJohn Forte 		 * fca_bind_port()
1021*fcf3ce44SJohn Forte 		 */
1022*fcf3ce44SJohn Forte 		vpd->port_num[0] = 0;
1023*fcf3ce44SJohn Forte 		vpd->port_index = 0;
1024*fcf3ce44SJohn Forte 	}
1025*fcf3ce44SJohn Forte 	/* Make first attempt to set a port index   */
1026*fcf3ce44SJohn Forte 	/* Check if this is a multifunction adapter */
1027*fcf3ce44SJohn Forte 	if ((vpd->port_index == -1) &&
1028*fcf3ce44SJohn Forte 	    (hba->model_info.chip >= EMLXS_THOR_CHIP)) {
1029*fcf3ce44SJohn Forte 		char *buffer;
1030*fcf3ce44SJohn Forte 		int32_t i;
1031*fcf3ce44SJohn Forte 
1032*fcf3ce44SJohn Forte 		/* The port address looks like this: */
1033*fcf3ce44SJohn Forte 		/* 1 - for port index 0   */
1034*fcf3ce44SJohn Forte 		/* 1,1 - for port index 1 */
1035*fcf3ce44SJohn Forte 		/* 1,2 - for port index 2 */
1036*fcf3ce44SJohn Forte 		buffer = ddi_get_name_addr(hba->dip);
1037*fcf3ce44SJohn Forte 
1038*fcf3ce44SJohn Forte 		if (buffer) {
1039*fcf3ce44SJohn Forte 			vpd->port_index = 0;
1040*fcf3ce44SJohn Forte 
1041*fcf3ce44SJohn Forte 			/* Reverse scan for a comma */
1042*fcf3ce44SJohn Forte 			for (i = strlen(buffer) - 1; i > 0; i--) {
1043*fcf3ce44SJohn Forte 				if (buffer[i] == ',') {
1044*fcf3ce44SJohn Forte 					/* Comma found - set index now */
1045*fcf3ce44SJohn Forte 					vpd->port_index =
1046*fcf3ce44SJohn Forte 					    emlxs_strtol(&buffer[i + 1], 10);
1047*fcf3ce44SJohn Forte 					break;
1048*fcf3ce44SJohn Forte 				}
1049*fcf3ce44SJohn Forte 			}
1050*fcf3ce44SJohn Forte 		}
1051*fcf3ce44SJohn Forte 	}
1052*fcf3ce44SJohn Forte 	/* Make final attempt to set a port index */
1053*fcf3ce44SJohn Forte 	if (vpd->port_index == -1) {
1054*fcf3ce44SJohn Forte 		dev_info_t *p_dip;
1055*fcf3ce44SJohn Forte 		dev_info_t *c_dip;
1056*fcf3ce44SJohn Forte 
1057*fcf3ce44SJohn Forte 		p_dip = ddi_get_parent(hba->dip);
1058*fcf3ce44SJohn Forte 		c_dip = ddi_get_child(p_dip);
1059*fcf3ce44SJohn Forte 
1060*fcf3ce44SJohn Forte 		vpd->port_index = 0;
1061*fcf3ce44SJohn Forte 		while (c_dip && (hba->dip != c_dip)) {
1062*fcf3ce44SJohn Forte 			c_dip = ddi_get_next_sibling(c_dip);
1063*fcf3ce44SJohn Forte 			vpd->port_index++;
1064*fcf3ce44SJohn Forte 		}
1065*fcf3ce44SJohn Forte 	}
1066*fcf3ce44SJohn Forte 	if (vpd->port_num[0] == 0) {
1067*fcf3ce44SJohn Forte 		if (hba->model_info.channels > 1) {
1068*fcf3ce44SJohn Forte 			(void) sprintf(vpd->port_num, "%d", vpd->port_index);
1069*fcf3ce44SJohn Forte 		}
1070*fcf3ce44SJohn Forte 	}
1071*fcf3ce44SJohn Forte 	if (vpd->id[0] == 0) {
1072*fcf3ce44SJohn Forte 		(void) strcpy(vpd->id, hba->model_info.model_desc);
1073*fcf3ce44SJohn Forte 	}
1074*fcf3ce44SJohn Forte 	if (vpd->manufacturer[0] == 0) {
1075*fcf3ce44SJohn Forte 		(void) strcpy(vpd->manufacturer, hba->model_info.manufacturer);
1076*fcf3ce44SJohn Forte 	}
1077*fcf3ce44SJohn Forte 	if (vpd->part_num[0] == 0) {
1078*fcf3ce44SJohn Forte 		(void) strcpy(vpd->part_num, hba->model_info.model);
1079*fcf3ce44SJohn Forte 	}
1080*fcf3ce44SJohn Forte 	if (vpd->model_desc[0] == 0) {
1081*fcf3ce44SJohn Forte 		(void) strcpy(vpd->model_desc, hba->model_info.model_desc);
1082*fcf3ce44SJohn Forte 	}
1083*fcf3ce44SJohn Forte 	if (vpd->model[0] == 0) {
1084*fcf3ce44SJohn Forte 		(void) strcpy(vpd->model, hba->model_info.model);
1085*fcf3ce44SJohn Forte 	}
1086*fcf3ce44SJohn Forte 	if (vpd->prog_types[0] == 0) {
1087*fcf3ce44SJohn Forte 		emlxs_build_prog_types(hba, vpd->prog_types);
1088*fcf3ce44SJohn Forte 	}
1089*fcf3ce44SJohn Forte 	/* Create the symbolic names */
1090*fcf3ce44SJohn Forte 	(void) sprintf(hba->snn, "Emulex %s FV%s DV%s %s",
1091*fcf3ce44SJohn Forte 	    hba->model_info.model, hba->vpd.fw_version, emlxs_version,
1092*fcf3ce44SJohn Forte 	    (char *)utsname.nodename);
1093*fcf3ce44SJohn Forte 
1094*fcf3ce44SJohn Forte 	(void) sprintf(hba->spn,
1095*fcf3ce44SJohn Forte 	    "Emulex PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1096*fcf3ce44SJohn Forte 	    hba->wwpn.nameType, hba->wwpn.IEEEextMsn, hba->wwpn.IEEEextLsb,
1097*fcf3ce44SJohn Forte 	    hba->wwpn.IEEE[0], hba->wwpn.IEEE[1], hba->wwpn.IEEE[2],
1098*fcf3ce44SJohn Forte 	    hba->wwpn.IEEE[3], hba->wwpn.IEEE[4], hba->wwpn.IEEE[5]);
1099*fcf3ce44SJohn Forte 
1100*fcf3ce44SJohn Forte 	if (cfg[CFG_NETWORK_ON].current) {
1101*fcf3ce44SJohn Forte 		if ((hba->sparam.portName.nameType != NAME_IEEE) ||
1102*fcf3ce44SJohn Forte 		    (hba->sparam.portName.IEEEextMsn != 0) ||
1103*fcf3ce44SJohn Forte 		    (hba->sparam.portName.IEEEextLsb != 0)) {
1104*fcf3ce44SJohn Forte 
1105*fcf3ce44SJohn Forte 			cfg[CFG_NETWORK_ON].current = 0;
1106*fcf3ce44SJohn Forte 
1107*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
1108*fcf3ce44SJohn Forte 			    "WWPN doesn't conform to IP profile: nameType=%x",
1109*fcf3ce44SJohn Forte 			    hba->sparam.portName.nameType);
1110*fcf3ce44SJohn Forte 		}
1111*fcf3ce44SJohn Forte 		/* Issue CONFIG FARP */
1112*fcf3ce44SJohn Forte 		emlxs_mb_config_farp(hba, mb);
1113*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
1114*fcf3ce44SJohn Forte 			/*
1115*fcf3ce44SJohn Forte 			 * Let it go through even if failed.
1116*fcf3ce44SJohn Forte 			 */
1117*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
1118*fcf3ce44SJohn Forte 			    "Unable to configure FARP. Mailbox cmd=%x "
1119*fcf3ce44SJohn Forte 			    "status=%x", mb->mbxCommand, mb->mbxStatus);
1120*fcf3ce44SJohn Forte 		}
1121*fcf3ce44SJohn Forte 	}
1122*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
1123*fcf3ce44SJohn Forte 	/* Configure MSI map if required */
1124*fcf3ce44SJohn Forte 	if (hba->intr_count > 1) {
1125*fcf3ce44SJohn Forte 		emlxs_mb_config_msix(hba, mb, hba->intr_map, hba->intr_count);
1126*fcf3ce44SJohn Forte 
1127*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) == MBX_SUCCESS) {
1128*fcf3ce44SJohn Forte 			goto msi_configured;
1129*fcf3ce44SJohn Forte 		}
1130*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1131*fcf3ce44SJohn Forte 		    "Unable to config MSIX.  Mailbox cmd=0x%x status=0x%x",
1132*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
1133*fcf3ce44SJohn Forte 
1134*fcf3ce44SJohn Forte 		emlxs_mb_config_msi(hba, mb, hba->intr_map, hba->intr_count);
1135*fcf3ce44SJohn Forte 
1136*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) == MBX_SUCCESS) {
1137*fcf3ce44SJohn Forte 			goto msi_configured;
1138*fcf3ce44SJohn Forte 		}
1139*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1140*fcf3ce44SJohn Forte 		    "Unable to config MSI.  Mailbox cmd=0x%x status=0x%x",
1141*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
1142*fcf3ce44SJohn Forte 
1143*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1144*fcf3ce44SJohn Forte 		    "Attempting single interrupt mode...");
1145*fcf3ce44SJohn Forte 
1146*fcf3ce44SJohn Forte 		/* First cleanup old interrupts */
1147*fcf3ce44SJohn Forte 		(void) emlxs_msi_remove(hba);
1148*fcf3ce44SJohn Forte 		(void) emlxs_msi_uninit(hba);
1149*fcf3ce44SJohn Forte 
1150*fcf3ce44SJohn Forte 		status = emlxs_msi_init(hba, 1);
1151*fcf3ce44SJohn Forte 
1152*fcf3ce44SJohn Forte 		if (status != DDI_SUCCESS) {
1153*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1154*fcf3ce44SJohn Forte 			    "Unable to initialize interrupt. status=%d",
1155*fcf3ce44SJohn Forte 			    status);
1156*fcf3ce44SJohn Forte 
1157*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
1158*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1159*fcf3ce44SJohn Forte 			emlxs_ffcleanup(hba);
1160*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
1161*fcf3ce44SJohn Forte 
1162*fcf3ce44SJohn Forte 			return (EIO);
1163*fcf3ce44SJohn Forte 		}
1164*fcf3ce44SJohn Forte 		/*
1165*fcf3ce44SJohn Forte 		 * Reset adapter - The adapter needs to be reset because the
1166*fcf3ce44SJohn Forte 		 * bus cannot handle the MSI change without handshaking with
1167*fcf3ce44SJohn Forte 		 * the adapter again
1168*fcf3ce44SJohn Forte 		 */
1169*fcf3ce44SJohn Forte 
1170*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1171*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
1172*fcf3ce44SJohn Forte 		fw_check = 0;
1173*fcf3ce44SJohn Forte 		goto reset;
1174*fcf3ce44SJohn Forte 	}
1175*fcf3ce44SJohn Forte msi_configured:
1176*fcf3ce44SJohn Forte 
1177*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
1178*fcf3ce44SJohn Forte 
1179*fcf3ce44SJohn Forte 	/*
1180*fcf3ce44SJohn Forte 	 * We always disable the firmware traffic cop feature
1181*fcf3ce44SJohn Forte 	 */
1182*fcf3ce44SJohn Forte 	if (emlxs_disable_traffic_cop) {
1183*fcf3ce44SJohn Forte 		emlxs_disable_tc(hba, (MAILBOX *) mb);
1184*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
1185*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1186*fcf3ce44SJohn Forte 			    "Unable to disable traffic cop. Mailbox cmd=%x "
1187*fcf3ce44SJohn Forte 			    "status=%x", mb->mbxCommand, mb->mbxStatus);
1188*fcf3ce44SJohn Forte 
1189*fcf3ce44SJohn Forte 			(void) EMLXS_INTR_REMOVE(hba);
1190*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
1191*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1192*fcf3ce44SJohn Forte 			emlxs_ffcleanup(hba);
1193*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
1194*fcf3ce44SJohn Forte 
1195*fcf3ce44SJohn Forte 			return (EIO);
1196*fcf3ce44SJohn Forte 		}
1197*fcf3ce44SJohn Forte 	}
1198*fcf3ce44SJohn Forte 	emlxs_mb_read_config(hba, (MAILBOX *) mb);
1199*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
1200*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1201*fcf3ce44SJohn Forte 		    "Unable to read configuration.  Mailbox cmd=%x status=%x",
1202*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
1203*fcf3ce44SJohn Forte 
1204*fcf3ce44SJohn Forte 		(void) EMLXS_INTR_REMOVE(hba);
1205*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
1206*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1207*fcf3ce44SJohn Forte 		emlxs_ffcleanup(hba);
1208*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
1209*fcf3ce44SJohn Forte 
1210*fcf3ce44SJohn Forte 		return (EIO);
1211*fcf3ce44SJohn Forte 	}
1212*fcf3ce44SJohn Forte 	/* Save the link speed capabilities */
1213*fcf3ce44SJohn Forte 	vpd->link_speed = mb->un.varRdConfig.lmt;
1214*fcf3ce44SJohn Forte 	emlxs_process_link_speed(hba);
1215*fcf3ce44SJohn Forte 
1216*fcf3ce44SJohn Forte 	/* Set the io throttle */
1217*fcf3ce44SJohn Forte 	hba->io_throttle = mb->un.varRdConfig.max_xri - IO_THROTTLE_RESERVE;
1218*fcf3ce44SJohn Forte 
1219*fcf3ce44SJohn Forte 	/* Set the max node count */
1220*fcf3ce44SJohn Forte 	if (cfg[CFG_NUM_NODES].current > 0) {
1221*fcf3ce44SJohn Forte 		hba->max_nodes =
1222*fcf3ce44SJohn Forte 		    min(cfg[CFG_NUM_NODES].current, mb->un.varRdConfig.max_rpi);
1223*fcf3ce44SJohn Forte 	} else {
1224*fcf3ce44SJohn Forte 		hba->max_nodes = mb->un.varRdConfig.max_rpi;
1225*fcf3ce44SJohn Forte 	}
1226*fcf3ce44SJohn Forte 
1227*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_LINK_DOWN);
1228*fcf3ce44SJohn Forte 
1229*fcf3ce44SJohn Forte 	/* Enable mailbox, error attention interrupts */
1230*fcf3ce44SJohn Forte 	status = (uint32_t)(HC_MBINT_ENA | HC_ERINT_ENA);
1231*fcf3ce44SJohn Forte 
1232*fcf3ce44SJohn Forte 	/* Enable ring interrupts */
1233*fcf3ce44SJohn Forte 	if (hba->ring_count >= 4) {
1234*fcf3ce44SJohn Forte 		status |= (HC_R3INT_ENA | HC_R2INT_ENA | HC_R1INT_ENA |
1235*fcf3ce44SJohn Forte 		    HC_R0INT_ENA);
1236*fcf3ce44SJohn Forte 	} else if (hba->ring_count == 3) {
1237*fcf3ce44SJohn Forte 		status |= (HC_R2INT_ENA | HC_R1INT_ENA | HC_R0INT_ENA);
1238*fcf3ce44SJohn Forte 	} else if (hba->ring_count == 2) {
1239*fcf3ce44SJohn Forte 		status |= (HC_R1INT_ENA | HC_R0INT_ENA);
1240*fcf3ce44SJohn Forte 	} else if (hba->ring_count == 1) {
1241*fcf3ce44SJohn Forte 		status |= (HC_R0INT_ENA);
1242*fcf3ce44SJohn Forte 	}
1243*fcf3ce44SJohn Forte 	hba->hc_copy = status;
1244*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
1245*fcf3ce44SJohn Forte 
1246*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
1247*fcf3ce44SJohn Forte 
1248*fcf3ce44SJohn Forte 	if (hba->flag & FC_HBQ_ENABLED) {
1249*fcf3ce44SJohn Forte 		if (hba->tgt_mode) {
1250*fcf3ce44SJohn Forte 			if (emlxs_hbq_setup(hba, EMLXS_FCT_HBQ_ID)) {
1251*fcf3ce44SJohn Forte 				return (ENOMEM);
1252*fcf3ce44SJohn Forte 			}
1253*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1254*fcf3ce44SJohn Forte 			    "FCT Ring: Posted %d buffers.", MEM_FCTBUF_COUNT);
1255*fcf3ce44SJohn Forte 		}
1256*fcf3ce44SJohn Forte 		if (cfg[CFG_NETWORK_ON].current) {
1257*fcf3ce44SJohn Forte 			if (emlxs_hbq_setup(hba, EMLXS_IP_HBQ_ID)) {
1258*fcf3ce44SJohn Forte 				return (ENOMEM);
1259*fcf3ce44SJohn Forte 			}
1260*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1261*fcf3ce44SJohn Forte 			    "IP  Ring: Posted %d buffers.", MEM_IPBUF_COUNT);
1262*fcf3ce44SJohn Forte 		}
1263*fcf3ce44SJohn Forte 		if (emlxs_hbq_setup(hba, EMLXS_ELS_HBQ_ID)) {
1264*fcf3ce44SJohn Forte 			return (ENOMEM);
1265*fcf3ce44SJohn Forte 		}
1266*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1267*fcf3ce44SJohn Forte 		    "ELS Ring: Posted %d buffers.", MEM_ELSBUF_COUNT);
1268*fcf3ce44SJohn Forte 
1269*fcf3ce44SJohn Forte 		if (emlxs_hbq_setup(hba, EMLXS_CT_HBQ_ID)) {
1270*fcf3ce44SJohn Forte 			return (ENOMEM);
1271*fcf3ce44SJohn Forte 		}
1272*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1273*fcf3ce44SJohn Forte 		    "CT  Ring: Posted %d buffers.", MEM_CTBUF_COUNT);
1274*fcf3ce44SJohn Forte 	} else
1275*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
1276*fcf3ce44SJohn Forte 	{
1277*fcf3ce44SJohn Forte 		if (hba->tgt_mode) {
1278*fcf3ce44SJohn Forte 			/* Post the FCT unsol buffers */
1279*fcf3ce44SJohn Forte 			rp = &hba->ring[FC_FCT_RING];
1280*fcf3ce44SJohn Forte 			for (j = 0; j < MEM_FCTBUF_COUNT; j += 2) {
1281*fcf3ce44SJohn Forte 				(void) emlxs_post_buffer(hba, rp, 2);
1282*fcf3ce44SJohn Forte 			}
1283*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1284*fcf3ce44SJohn Forte 			    "FCP Ring: Posted %d buffers.", MEM_FCTBUF_COUNT);
1285*fcf3ce44SJohn Forte 		}
1286*fcf3ce44SJohn Forte 		if (cfg[CFG_NETWORK_ON].current) {
1287*fcf3ce44SJohn Forte 			/* Post the IP unsol buffers */
1288*fcf3ce44SJohn Forte 			rp = &hba->ring[FC_IP_RING];
1289*fcf3ce44SJohn Forte 			for (j = 0; j < MEM_IPBUF_COUNT; j += 2) {
1290*fcf3ce44SJohn Forte 				(void) emlxs_post_buffer(hba, rp, 2);
1291*fcf3ce44SJohn Forte 			}
1292*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1293*fcf3ce44SJohn Forte 			    "IP  Ring: Posted %d buffers.", MEM_IPBUF_COUNT);
1294*fcf3ce44SJohn Forte 		}
1295*fcf3ce44SJohn Forte 		/* Post the ELS unsol buffers */
1296*fcf3ce44SJohn Forte 		rp = &hba->ring[FC_ELS_RING];
1297*fcf3ce44SJohn Forte 		for (j = 0; j < MEM_ELSBUF_COUNT; j += 2) {
1298*fcf3ce44SJohn Forte 			(void) emlxs_post_buffer(hba, rp, 2);
1299*fcf3ce44SJohn Forte 		}
1300*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1301*fcf3ce44SJohn Forte 		    "ELS Ring: Posted %d buffers.", MEM_ELSBUF_COUNT);
1302*fcf3ce44SJohn Forte 
1303*fcf3ce44SJohn Forte 
1304*fcf3ce44SJohn Forte 		/* Post the CT unsol buffers */
1305*fcf3ce44SJohn Forte 		rp = &hba->ring[FC_CT_RING];
1306*fcf3ce44SJohn Forte 		for (j = 0; j < MEM_CTBUF_COUNT; j += 2) {
1307*fcf3ce44SJohn Forte 			(void) emlxs_post_buffer(hba, rp, 2);
1308*fcf3ce44SJohn Forte 		}
1309*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1310*fcf3ce44SJohn Forte 		    "CT  Ring: Posted %d buffers.", MEM_CTBUF_COUNT);
1311*fcf3ce44SJohn Forte 	}
1312*fcf3ce44SJohn Forte 
1313*fcf3ce44SJohn Forte 	/* Register for async events */
1314*fcf3ce44SJohn Forte 	emlxs_mb_async_event(hba, mb);
1315*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
1316*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1317*fcf3ce44SJohn Forte 		    "Async events disabled. Mailbox status=%x", mb->mbxStatus);
1318*fcf3ce44SJohn Forte 	} else {
1319*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1320*fcf3ce44SJohn Forte 		    "Async events enabled.");
1321*fcf3ce44SJohn Forte 		hba->flag |= FC_ASYNC_EVENTS;
1322*fcf3ce44SJohn Forte 	}
1323*fcf3ce44SJohn Forte 
1324*fcf3ce44SJohn Forte 
1325*fcf3ce44SJohn Forte 	/*
1326*fcf3ce44SJohn Forte 	 * Setup and issue mailbox INITIALIZE LINK command At this point, the
1327*fcf3ce44SJohn Forte 	 * interrupt will be generated by the HW
1328*fcf3ce44SJohn Forte 	 */
1329*fcf3ce44SJohn Forte 	emlxs_mb_init_link(hba, mb, cfg[CFG_TOPOLOGY].current,
1330*fcf3ce44SJohn Forte 	    cfg[CFG_LINK_SPEED].current);
1331*fcf3ce44SJohn Forte 
1332*fcf3ce44SJohn Forte 	rval = emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0);
1333*fcf3ce44SJohn Forte 
1334*fcf3ce44SJohn Forte 	if (rval != MBX_SUCCESS && rval != MBX_BUSY) {
1335*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1336*fcf3ce44SJohn Forte 		    "Unable to initialize link.  Mailbox cmd=%x status=%x",
1337*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
1338*fcf3ce44SJohn Forte 
1339*fcf3ce44SJohn Forte 		(void) EMLXS_INTR_REMOVE(hba);
1340*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
1341*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1342*fcf3ce44SJohn Forte 		emlxs_ffcleanup(hba);
1343*fcf3ce44SJohn Forte 		(void) emlxs_mem_free_buffer(hba);
1344*fcf3ce44SJohn Forte 
1345*fcf3ce44SJohn Forte 		return (EIO);
1346*fcf3ce44SJohn Forte 	}
1347*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1348*fcf3ce44SJohn Forte 
1349*fcf3ce44SJohn Forte 	/*
1350*fcf3ce44SJohn Forte 	 * Enable link attention interrupt
1351*fcf3ce44SJohn Forte 	 */
1352*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1353*fcf3ce44SJohn Forte 	hba->hc_copy |= HC_LAINT_ENA;
1354*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
1355*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1356*fcf3ce44SJohn Forte 
1357*fcf3ce44SJohn Forte 
1358*fcf3ce44SJohn Forte 	/* Wait for link to come up */
1359*fcf3ce44SJohn Forte 	i = cfg[CFG_LINKUP_DELAY].current;
1360*fcf3ce44SJohn Forte 	while (i && (hba->state < FC_LINK_UP)) {
1361*fcf3ce44SJohn Forte 		/* Check for hardware error */
1362*fcf3ce44SJohn Forte 		if (hba->state == FC_ERROR) {
1363*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1364*fcf3ce44SJohn Forte 			    "Adapter error.", mb->mbxCommand, mb->mbxStatus);
1365*fcf3ce44SJohn Forte 
1366*fcf3ce44SJohn Forte 			(void) EMLXS_INTR_REMOVE(hba);
1367*fcf3ce44SJohn Forte 			emlxs_ffcleanup(hba);
1368*fcf3ce44SJohn Forte 			(void) emlxs_mem_free_buffer(hba);
1369*fcf3ce44SJohn Forte 
1370*fcf3ce44SJohn Forte 			return (EIO);
1371*fcf3ce44SJohn Forte 		}
1372*fcf3ce44SJohn Forte 		DELAYMS(1000);
1373*fcf3ce44SJohn Forte 		i--;
1374*fcf3ce44SJohn Forte 	}
1375*fcf3ce44SJohn Forte 
1376*fcf3ce44SJohn Forte out:
1377*fcf3ce44SJohn Forte 
1378*fcf3ce44SJohn Forte 	/*
1379*fcf3ce44SJohn Forte 	 * The leadvile driver will now handle the FLOGI at the driver level
1380*fcf3ce44SJohn Forte 	 */
1381*fcf3ce44SJohn Forte 
1382*fcf3ce44SJohn Forte 	return (0);
1383*fcf3ce44SJohn Forte 
1384*fcf3ce44SJohn Forte } /* emlxs_ffinit() */
1385*fcf3ce44SJohn Forte 
1386*fcf3ce44SJohn Forte 
1387*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
1388*fcf3ce44SJohn Forte 
1389*fcf3ce44SJohn Forte /* EMLXS_INTR_INIT */
1390*fcf3ce44SJohn Forte int32_t
1391*fcf3ce44SJohn Forte emlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
1392*fcf3ce44SJohn Forte {
1393*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1394*fcf3ce44SJohn Forte 	int32_t pass = 0;
1395*fcf3ce44SJohn Forte 	int32_t type = 0;
1396*fcf3ce44SJohn Forte 	char s_type[16];
1397*fcf3ce44SJohn Forte 	int32_t types;
1398*fcf3ce44SJohn Forte 	int32_t count;
1399*fcf3ce44SJohn Forte 	int32_t nintrs;
1400*fcf3ce44SJohn Forte 	int32_t mode;
1401*fcf3ce44SJohn Forte 	int32_t actual;
1402*fcf3ce44SJohn Forte 	int32_t new_actual;
1403*fcf3ce44SJohn Forte 	int32_t i;
1404*fcf3ce44SJohn Forte 	int32_t ret;
1405*fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable = NULL;
1406*fcf3ce44SJohn Forte 	ddi_intr_handle_t *new_htable = NULL;
1407*fcf3ce44SJohn Forte 	uint32_t *intr_pri = NULL;
1408*fcf3ce44SJohn Forte 	int32_t *intr_cap = NULL;
1409*fcf3ce44SJohn Forte 	int32_t hilevel_pri;
1410*fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1411*fcf3ce44SJohn Forte 	char buf[64];
1412*fcf3ce44SJohn Forte 
1413*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
1414*fcf3ce44SJohn Forte 		return (emlxs_intx_init(hba, max));
1415*fcf3ce44SJohn Forte 	}
1416*fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_MSI_INITED) {
1417*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
1418*fcf3ce44SJohn Forte 	}
1419*fcf3ce44SJohn Forte 	/* Set max interrupt count if not specified */
1420*fcf3ce44SJohn Forte 	if (max == 0) {
1421*fcf3ce44SJohn Forte 		if ((cfg[CFG_MSI_MODE].current == 2) ||
1422*fcf3ce44SJohn Forte 		    (cfg[CFG_MSI_MODE].current == 3)) {
1423*fcf3ce44SJohn Forte 			max = EMLXS_MSI_MAX_INTRS;
1424*fcf3ce44SJohn Forte 		} else {
1425*fcf3ce44SJohn Forte 			max = 1;
1426*fcf3ce44SJohn Forte 		}
1427*fcf3ce44SJohn Forte 	}
1428*fcf3ce44SJohn Forte 	/* Filter max interrupt count with adapter model specification */
1429*fcf3ce44SJohn Forte 	if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
1430*fcf3ce44SJohn Forte 		max = hba->model_info.intr_limit;
1431*fcf3ce44SJohn Forte 	}
1432*fcf3ce44SJohn Forte 	/* Get the available interrupt types from the kernel */
1433*fcf3ce44SJohn Forte 	types = 0;
1434*fcf3ce44SJohn Forte 	ret = ddi_intr_get_supported_types(hba->dip, &types);
1435*fcf3ce44SJohn Forte 
1436*fcf3ce44SJohn Forte 	if ((ret != DDI_SUCCESS)) {
1437*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1438*fcf3ce44SJohn Forte 		    "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
1439*fcf3ce44SJohn Forte 
1440*fcf3ce44SJohn Forte 		/* Default to fixed type */
1441*fcf3ce44SJohn Forte 		types = DDI_INTR_TYPE_FIXED;
1442*fcf3ce44SJohn Forte 	}
1443*fcf3ce44SJohn Forte 	/* Check if fixed interrupts are being forced */
1444*fcf3ce44SJohn Forte 	if (cfg[CFG_MSI_MODE].current == 0) {
1445*fcf3ce44SJohn Forte 		types &= DDI_INTR_TYPE_FIXED;
1446*fcf3ce44SJohn Forte 	}
1447*fcf3ce44SJohn Forte 	/* Check if MSI interrupts are being forced */
1448*fcf3ce44SJohn Forte 	else if ((cfg[CFG_MSI_MODE].current == 1) ||
1449*fcf3ce44SJohn Forte 	    (cfg[CFG_MSI_MODE].current == 2)) {
1450*fcf3ce44SJohn Forte 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
1451*fcf3ce44SJohn Forte 	}
1452*fcf3ce44SJohn Forte begin:
1453*fcf3ce44SJohn Forte 
1454*fcf3ce44SJohn Forte 	/* Set interrupt type and interrupt count */
1455*fcf3ce44SJohn Forte 	type = 0;
1456*fcf3ce44SJohn Forte 
1457*fcf3ce44SJohn Forte 	/* Check if MSIX is fully supported */
1458*fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_MSIX) &&
1459*fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
1460*fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
1461*fcf3ce44SJohn Forte 		nintrs = 0;
1462*fcf3ce44SJohn Forte 		ret =
1463*fcf3ce44SJohn Forte 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX, &nintrs);
1464*fcf3ce44SJohn Forte 
1465*fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS && nintrs) {
1466*fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_MSIX;
1467*fcf3ce44SJohn Forte 			(void) strcpy(s_type, "TYPE_MSIX");
1468*fcf3ce44SJohn Forte 			goto initialize;
1469*fcf3ce44SJohn Forte 		}
1470*fcf3ce44SJohn Forte 	}
1471*fcf3ce44SJohn Forte 	/* Check if MSI is fully supported */
1472*fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_MSI) &&
1473*fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
1474*fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
1475*fcf3ce44SJohn Forte 		nintrs = 0;
1476*fcf3ce44SJohn Forte 		ret = ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
1477*fcf3ce44SJohn Forte 
1478*fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS && nintrs) {
1479*fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_MSI;
1480*fcf3ce44SJohn Forte 			(void) strcpy(s_type, "TYPE_MSI");
1481*fcf3ce44SJohn Forte 			goto initialize;
1482*fcf3ce44SJohn Forte 		}
1483*fcf3ce44SJohn Forte 	}
1484*fcf3ce44SJohn Forte 	/* Check if fixed interrupts are fully supported */
1485*fcf3ce44SJohn Forte 	if ((types & DDI_INTR_TYPE_FIXED) &&
1486*fcf3ce44SJohn Forte 	    (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
1487*fcf3ce44SJohn Forte 		/* Get the max interrupt count from the adapter */
1488*fcf3ce44SJohn Forte 		nintrs = 0;
1489*fcf3ce44SJohn Forte 		ret =
1490*fcf3ce44SJohn Forte 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED, &nintrs);
1491*fcf3ce44SJohn Forte 
1492*fcf3ce44SJohn Forte 		if (ret == DDI_SUCCESS) {
1493*fcf3ce44SJohn Forte 			type = DDI_INTR_TYPE_FIXED;
1494*fcf3ce44SJohn Forte 			(void) strcpy(s_type, "TYPE_FIXED");
1495*fcf3ce44SJohn Forte 			goto initialize;
1496*fcf3ce44SJohn Forte 		}
1497*fcf3ce44SJohn Forte 	}
1498*fcf3ce44SJohn Forte 	goto init_failed;
1499*fcf3ce44SJohn Forte 
1500*fcf3ce44SJohn Forte 
1501*fcf3ce44SJohn Forte initialize:
1502*fcf3ce44SJohn Forte 
1503*fcf3ce44SJohn Forte 	pass++;
1504*fcf3ce44SJohn Forte 	mode = 0;
1505*fcf3ce44SJohn Forte 	actual = 0;
1506*fcf3ce44SJohn Forte 	htable = NULL;
1507*fcf3ce44SJohn Forte 	intr_pri = NULL;
1508*fcf3ce44SJohn Forte 	intr_cap = NULL;
1509*fcf3ce44SJohn Forte 	hilevel_pri = 0;
1510*fcf3ce44SJohn Forte 
1511*fcf3ce44SJohn Forte 	if (pass == 1) {
1512*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1513*fcf3ce44SJohn Forte 		    "MSI: %s: mode=%d types=0x%x nintrs=%d",
1514*fcf3ce44SJohn Forte 		    s_type, cfg[CFG_MSI_MODE].current, types, nintrs);
1515*fcf3ce44SJohn Forte 	}
1516*fcf3ce44SJohn Forte 	/* Validate interrupt count */
1517*fcf3ce44SJohn Forte 	count = min(nintrs, max);
1518*fcf3ce44SJohn Forte 
1519*fcf3ce44SJohn Forte 	if (count >= 8) {
1520*fcf3ce44SJohn Forte 		count = 8;
1521*fcf3ce44SJohn Forte 	} else if (count >= 4) {
1522*fcf3ce44SJohn Forte 		count = 4;
1523*fcf3ce44SJohn Forte 	} else if (count >= 2) {
1524*fcf3ce44SJohn Forte 		count = 2;
1525*fcf3ce44SJohn Forte 	} else {
1526*fcf3ce44SJohn Forte 		count = 1;
1527*fcf3ce44SJohn Forte 	}
1528*fcf3ce44SJohn Forte 
1529*fcf3ce44SJohn Forte 	/* Allocate an array of interrupt handles */
1530*fcf3ce44SJohn Forte 	htable =
1531*fcf3ce44SJohn Forte 	    kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)), KM_SLEEP);
1532*fcf3ce44SJohn Forte 
1533*fcf3ce44SJohn Forte 	if (htable == NULL) {
1534*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1535*fcf3ce44SJohn Forte 		    "MSI: Unable to allocate interrupt handle table");
1536*fcf3ce44SJohn Forte 
1537*fcf3ce44SJohn Forte 		goto init_failed;
1538*fcf3ce44SJohn Forte 	}
1539*fcf3ce44SJohn Forte 	/* Allocate 'count' interrupts */
1540*fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
1541*fcf3ce44SJohn Forte 	    &actual, DDI_INTR_ALLOC_NORMAL);
1542*fcf3ce44SJohn Forte 
1543*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1544*fcf3ce44SJohn Forte 	    "MSI: %s: count=%d actual=%d", s_type, count, actual);
1545*fcf3ce44SJohn Forte 
1546*fcf3ce44SJohn Forte 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
1547*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1548*fcf3ce44SJohn Forte 		    "MSI: Unable to allocate interrupts. error=%d", ret);
1549*fcf3ce44SJohn Forte 
1550*fcf3ce44SJohn Forte 		goto init_failed;
1551*fcf3ce44SJohn Forte 	}
1552*fcf3ce44SJohn Forte 	if (actual != count) {
1553*fcf3ce44SJohn Forte 		/* Validate actual count */
1554*fcf3ce44SJohn Forte 		if (actual >= 8) {
1555*fcf3ce44SJohn Forte 			new_actual = 8;
1556*fcf3ce44SJohn Forte 		} else if (actual >= 4) {
1557*fcf3ce44SJohn Forte 			new_actual = 4;
1558*fcf3ce44SJohn Forte 		} else if (actual >= 2) {
1559*fcf3ce44SJohn Forte 			new_actual = 2;
1560*fcf3ce44SJohn Forte 		} else {
1561*fcf3ce44SJohn Forte 			new_actual = 1;
1562*fcf3ce44SJohn Forte 		}
1563*fcf3ce44SJohn Forte 
1564*fcf3ce44SJohn Forte 		if (new_actual < actual) {
1565*fcf3ce44SJohn Forte 			/* Free extra handles */
1566*fcf3ce44SJohn Forte 			for (i = new_actual; i < actual; i++) {
1567*fcf3ce44SJohn Forte 				(void) ddi_intr_free(htable[i]);
1568*fcf3ce44SJohn Forte 			}
1569*fcf3ce44SJohn Forte 
1570*fcf3ce44SJohn Forte 			actual = new_actual;
1571*fcf3ce44SJohn Forte 		}
1572*fcf3ce44SJohn Forte 		/* Allocate a new array of interrupt handles */
1573*fcf3ce44SJohn Forte 		new_htable =
1574*fcf3ce44SJohn Forte 		    kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
1575*fcf3ce44SJohn Forte 		    KM_SLEEP);
1576*fcf3ce44SJohn Forte 
1577*fcf3ce44SJohn Forte 		if (new_htable == NULL) {
1578*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1579*fcf3ce44SJohn Forte 			    "MSI: Unable to allocate new interrupt handle "
1580*fcf3ce44SJohn Forte 			    "table");
1581*fcf3ce44SJohn Forte 
1582*fcf3ce44SJohn Forte 			goto init_failed;
1583*fcf3ce44SJohn Forte 		}
1584*fcf3ce44SJohn Forte 		/* Copy old array to new array */
1585*fcf3ce44SJohn Forte 		bcopy((uint8_t *)htable, (uint8_t *)new_htable,
1586*fcf3ce44SJohn Forte 		    (actual * sizeof (ddi_intr_handle_t)));
1587*fcf3ce44SJohn Forte 
1588*fcf3ce44SJohn Forte 		/* Free the old array */
1589*fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
1590*fcf3ce44SJohn Forte 
1591*fcf3ce44SJohn Forte 		htable = new_htable;
1592*fcf3ce44SJohn Forte 		count = actual;
1593*fcf3ce44SJohn Forte 	}
1594*fcf3ce44SJohn Forte 	/* Allocate interrupt priority table */
1595*fcf3ce44SJohn Forte 	intr_pri =
1596*fcf3ce44SJohn Forte 	    (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
1597*fcf3ce44SJohn Forte 	    KM_SLEEP);
1598*fcf3ce44SJohn Forte 
1599*fcf3ce44SJohn Forte 	if (intr_pri == NULL) {
1600*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1601*fcf3ce44SJohn Forte 		    "MSI: Unable to allocate interrupt priority table");
1602*fcf3ce44SJohn Forte 
1603*fcf3ce44SJohn Forte 		goto init_failed;
1604*fcf3ce44SJohn Forte 	}
1605*fcf3ce44SJohn Forte 	/* Allocate interrupt capability table */
1606*fcf3ce44SJohn Forte 	intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
1607*fcf3ce44SJohn Forte 
1608*fcf3ce44SJohn Forte 	if (intr_cap == NULL) {
1609*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1610*fcf3ce44SJohn Forte 		    "MSI: Unable to allocate interrupt capability table");
1611*fcf3ce44SJohn Forte 
1612*fcf3ce44SJohn Forte 		goto init_failed;
1613*fcf3ce44SJohn Forte 	}
1614*fcf3ce44SJohn Forte 	/* Get minimum hilevel priority */
1615*fcf3ce44SJohn Forte 	hilevel_pri = ddi_intr_get_hilevel_pri();
1616*fcf3ce44SJohn Forte 
1617*fcf3ce44SJohn Forte 	/* Fill the priority and capability tables */
1618*fcf3ce44SJohn Forte 	for (i = 0; i < count; ++i) {
1619*fcf3ce44SJohn Forte 		ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
1620*fcf3ce44SJohn Forte 
1621*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1622*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1623*fcf3ce44SJohn Forte 			    "MSI: ddi_intr_get_pri(%d) failed. "
1624*fcf3ce44SJohn Forte 			    "handle=%p ret=%d", i, &htable[i], ret);
1625*fcf3ce44SJohn Forte 
1626*fcf3ce44SJohn Forte 			/* Clean up the interrupts */
1627*fcf3ce44SJohn Forte 			goto init_failed;
1628*fcf3ce44SJohn Forte 		}
1629*fcf3ce44SJohn Forte 		if (intr_pri[i] >= hilevel_pri) {
1630*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1631*fcf3ce44SJohn Forte 			    "MSI: Interrupt(%d) level too high. "
1632*fcf3ce44SJohn Forte 			    "pri=0x%x hilevel=0x%x",
1633*fcf3ce44SJohn Forte 			    i, intr_pri[i], hilevel_pri);
1634*fcf3ce44SJohn Forte 
1635*fcf3ce44SJohn Forte 			/* Clean up the interrupts */
1636*fcf3ce44SJohn Forte 			goto init_failed;
1637*fcf3ce44SJohn Forte 		}
1638*fcf3ce44SJohn Forte 		ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
1639*fcf3ce44SJohn Forte 
1640*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1641*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1642*fcf3ce44SJohn Forte 			    "MSI: ddi_intr_get_cap(%d) failed. handle=%p "
1643*fcf3ce44SJohn Forte 			    "ret=%d", i, &htable[i], ret);
1644*fcf3ce44SJohn Forte 
1645*fcf3ce44SJohn Forte 			/* Clean up the interrupts */
1646*fcf3ce44SJohn Forte 			goto init_failed;
1647*fcf3ce44SJohn Forte 		}
1648*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1649*fcf3ce44SJohn Forte 		    "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x",
1650*fcf3ce44SJohn Forte 		    s_type, i, intr_cap[i], intr_pri[i], hilevel_pri);
1651*fcf3ce44SJohn Forte 
1652*fcf3ce44SJohn Forte 	}
1653*fcf3ce44SJohn Forte 
1654*fcf3ce44SJohn Forte 	/* Set mode */
1655*fcf3ce44SJohn Forte 	switch (count) {
1656*fcf3ce44SJohn Forte 	case 8:
1657*fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE8;
1658*fcf3ce44SJohn Forte 		break;
1659*fcf3ce44SJohn Forte 
1660*fcf3ce44SJohn Forte 	case 4:
1661*fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE4;
1662*fcf3ce44SJohn Forte 		break;
1663*fcf3ce44SJohn Forte 
1664*fcf3ce44SJohn Forte 	case 2:
1665*fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE2;
1666*fcf3ce44SJohn Forte 		break;
1667*fcf3ce44SJohn Forte 
1668*fcf3ce44SJohn Forte 	default:
1669*fcf3ce44SJohn Forte 		mode = EMLXS_MSI_MODE1;
1670*fcf3ce44SJohn Forte 	}
1671*fcf3ce44SJohn Forte 
1672*fcf3ce44SJohn Forte 	/* Save the info */
1673*fcf3ce44SJohn Forte 	hba->intr_htable = htable;
1674*fcf3ce44SJohn Forte 	hba->intr_count = count;
1675*fcf3ce44SJohn Forte 	hba->intr_pri = intr_pri;
1676*fcf3ce44SJohn Forte 	hba->intr_cap = intr_cap;
1677*fcf3ce44SJohn Forte 	hba->intr_type = type;
1678*fcf3ce44SJohn Forte 	hba->intr_arg = (void *)(unsigned long) intr_pri[0];
1679*fcf3ce44SJohn Forte 	hba->intr_mask = emlxs_msi_mask[mode];
1680*fcf3ce44SJohn Forte 
1681*fcf3ce44SJohn Forte 	hba->intr_cond = 0;
1682*fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
1683*fcf3ce44SJohn Forte 		hba->intr_map[i] = emlxs_msi_map[mode][i];
1684*fcf3ce44SJohn Forte 		hba->intr_cond |= emlxs_msi_map[mode][i];
1685*fcf3ce44SJohn Forte 
1686*fcf3ce44SJohn Forte 		(void) sprintf(buf, "%s%d_msi%d mutex", DRIVER_NAME,
1687*fcf3ce44SJohn Forte 		    hba->ddiinst, i);
1688*fcf3ce44SJohn Forte 		mutex_init(&hba->intr_lock[i], buf, MUTEX_DRIVER,
1689*fcf3ce44SJohn Forte 		    (void *) hba->intr_arg);
1690*fcf3ce44SJohn Forte 	}
1691*fcf3ce44SJohn Forte 
1692*fcf3ce44SJohn Forte 	/* Set flag to indicate support */
1693*fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_MSI_INITED;
1694*fcf3ce44SJohn Forte 
1695*fcf3ce44SJohn Forte 	/* Create the interrupt threads */
1696*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_RINGS; i++) {
1697*fcf3ce44SJohn Forte 		(void) sprintf(buf, "%s%d_ring%d mutex", DRIVER_NAME,
1698*fcf3ce44SJohn Forte 		    hba->ddiinst, i);
1699*fcf3ce44SJohn Forte 		mutex_init(&hba->ring[i].rsp_lock, buf, MUTEX_DRIVER,
1700*fcf3ce44SJohn Forte 		    (void *) hba->intr_arg);
1701*fcf3ce44SJohn Forte 
1702*fcf3ce44SJohn Forte 		emlxs_thread_create(hba, &hba->ring[i].intr_thread);
1703*fcf3ce44SJohn Forte 	}
1704*fcf3ce44SJohn Forte 
1705*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
1706*fcf3ce44SJohn Forte 
1707*fcf3ce44SJohn Forte 
1708*fcf3ce44SJohn Forte init_failed:
1709*fcf3ce44SJohn Forte 
1710*fcf3ce44SJohn Forte 	if (intr_cap) {
1711*fcf3ce44SJohn Forte 		kmem_free(intr_cap, (count * sizeof (int32_t)));
1712*fcf3ce44SJohn Forte 	}
1713*fcf3ce44SJohn Forte 	if (intr_pri) {
1714*fcf3ce44SJohn Forte 		kmem_free(intr_pri, (count * sizeof (int32_t)));
1715*fcf3ce44SJohn Forte 	}
1716*fcf3ce44SJohn Forte 	if (htable) {
1717*fcf3ce44SJohn Forte 		/* Process the interrupt handlers */
1718*fcf3ce44SJohn Forte 		for (i = 0; i < actual; i++) {
1719*fcf3ce44SJohn Forte 			/* Free the handle[i] */
1720*fcf3ce44SJohn Forte 			(void) ddi_intr_free(htable[i]);
1721*fcf3ce44SJohn Forte 		}
1722*fcf3ce44SJohn Forte 
1723*fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
1724*fcf3ce44SJohn Forte 	}
1725*fcf3ce44SJohn Forte 	/* Initialize */
1726*fcf3ce44SJohn Forte 	hba->intr_htable = NULL;
1727*fcf3ce44SJohn Forte 	hba->intr_count = 0;
1728*fcf3ce44SJohn Forte 	hba->intr_pri = NULL;
1729*fcf3ce44SJohn Forte 	hba->intr_cap = NULL;
1730*fcf3ce44SJohn Forte 	hba->intr_type = 0;
1731*fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
1732*fcf3ce44SJohn Forte 	hba->intr_cond = 0;
1733*fcf3ce44SJohn Forte 	bzero(hba->intr_map, sizeof (hba->intr_map));
1734*fcf3ce44SJohn Forte 	bzero(hba->intr_lock, sizeof (hba->intr_lock));
1735*fcf3ce44SJohn Forte 
1736*fcf3ce44SJohn Forte 	if (type == DDI_INTR_TYPE_MSIX) {
1737*fcf3ce44SJohn Forte 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
1738*fcf3ce44SJohn Forte 		goto begin;
1739*fcf3ce44SJohn Forte 	} else if (type == DDI_INTR_TYPE_MSI) {
1740*fcf3ce44SJohn Forte 		types &= DDI_INTR_TYPE_FIXED;
1741*fcf3ce44SJohn Forte 		goto begin;
1742*fcf3ce44SJohn Forte 	}
1743*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1744*fcf3ce44SJohn Forte 	    "MSI: Unable to initialize interrupts");
1745*fcf3ce44SJohn Forte 
1746*fcf3ce44SJohn Forte 	return (DDI_FAILURE);
1747*fcf3ce44SJohn Forte 
1748*fcf3ce44SJohn Forte 
1749*fcf3ce44SJohn Forte } /* emlxs_msi_init() */
1750*fcf3ce44SJohn Forte 
1751*fcf3ce44SJohn Forte 
1752*fcf3ce44SJohn Forte /* EMLXS_INTR_UNINIT */
1753*fcf3ce44SJohn Forte int32_t
1754*fcf3ce44SJohn Forte emlxs_msi_uninit(emlxs_hba_t *hba)
1755*fcf3ce44SJohn Forte {
1756*fcf3ce44SJohn Forte 	uint32_t count;
1757*fcf3ce44SJohn Forte 	int32_t i;
1758*fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable;
1759*fcf3ce44SJohn Forte 	uint32_t *intr_pri;
1760*fcf3ce44SJohn Forte 	int32_t *intr_cap;
1761*fcf3ce44SJohn Forte 	int32_t ret;
1762*fcf3ce44SJohn Forte 
1763*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
1764*fcf3ce44SJohn Forte 		return (emlxs_intx_uninit(hba));
1765*fcf3ce44SJohn Forte 	}
1766*fcf3ce44SJohn Forte 	/*
1767*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "MSI:
1768*fcf3ce44SJohn Forte 	 * emlxs_msi_uninit called. flags=%x", hba->intr_flags);
1769*fcf3ce44SJohn Forte 	 */
1770*fcf3ce44SJohn Forte 
1771*fcf3ce44SJohn Forte 	/* Make sure interrupts have been removed first */
1772*fcf3ce44SJohn Forte 	if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
1773*fcf3ce44SJohn Forte 		ret = emlxs_msi_remove(hba);
1774*fcf3ce44SJohn Forte 
1775*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1776*fcf3ce44SJohn Forte 			return (ret);
1777*fcf3ce44SJohn Forte 		}
1778*fcf3ce44SJohn Forte 	}
1779*fcf3ce44SJohn Forte 	/* Check if the interrupts are still initialized */
1780*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
1781*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
1782*fcf3ce44SJohn Forte 	}
1783*fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_MSI_INITED;
1784*fcf3ce44SJohn Forte 
1785*fcf3ce44SJohn Forte 	/* Get handle table parameters */
1786*fcf3ce44SJohn Forte 	htable = hba->intr_htable;
1787*fcf3ce44SJohn Forte 	count = hba->intr_count;
1788*fcf3ce44SJohn Forte 	intr_pri = hba->intr_pri;
1789*fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
1790*fcf3ce44SJohn Forte 
1791*fcf3ce44SJohn Forte 	/* Clean up */
1792*fcf3ce44SJohn Forte 	hba->intr_count = 0;
1793*fcf3ce44SJohn Forte 	hba->intr_htable = NULL;
1794*fcf3ce44SJohn Forte 	hba->intr_pri = NULL;
1795*fcf3ce44SJohn Forte 	hba->intr_cap = NULL;
1796*fcf3ce44SJohn Forte 	hba->intr_type = 0;
1797*fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
1798*fcf3ce44SJohn Forte 	hba->intr_cond = 0;
1799*fcf3ce44SJohn Forte 	bzero(hba->intr_map, sizeof (hba->intr_map));
1800*fcf3ce44SJohn Forte 
1801*fcf3ce44SJohn Forte 	if (intr_cap) {
1802*fcf3ce44SJohn Forte 		kmem_free(intr_cap, (count * sizeof (int32_t)));
1803*fcf3ce44SJohn Forte 	}
1804*fcf3ce44SJohn Forte 	if (intr_pri) {
1805*fcf3ce44SJohn Forte 		kmem_free(intr_pri, (count * sizeof (int32_t)));
1806*fcf3ce44SJohn Forte 	}
1807*fcf3ce44SJohn Forte 	if (htable) {
1808*fcf3ce44SJohn Forte 		/* Process the interrupt handlers */
1809*fcf3ce44SJohn Forte 		for (i = 0; i < count; ++i) {
1810*fcf3ce44SJohn Forte 			/* Free the handle[i] */
1811*fcf3ce44SJohn Forte 			(void) ddi_intr_free(htable[i]);
1812*fcf3ce44SJohn Forte 		}
1813*fcf3ce44SJohn Forte 
1814*fcf3ce44SJohn Forte 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
1815*fcf3ce44SJohn Forte 	}
1816*fcf3ce44SJohn Forte 	/* Destroy the intr locks */
1817*fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
1818*fcf3ce44SJohn Forte 		mutex_destroy(&hba->intr_lock[i]);
1819*fcf3ce44SJohn Forte 	}
1820*fcf3ce44SJohn Forte 
1821*fcf3ce44SJohn Forte 	/* Destroy the interrupt threads */
1822*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_RINGS; i++) {
1823*fcf3ce44SJohn Forte 		emlxs_thread_destroy(&hba->ring[i].intr_thread);
1824*fcf3ce44SJohn Forte 		mutex_destroy(&hba->ring[i].rsp_lock);
1825*fcf3ce44SJohn Forte 	}
1826*fcf3ce44SJohn Forte 
1827*fcf3ce44SJohn Forte 	/*
1828*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "MSI:
1829*fcf3ce44SJohn Forte 	 * emlxs_msi_uninit done. flags=%x", hba->intr_flags);
1830*fcf3ce44SJohn Forte 	 */
1831*fcf3ce44SJohn Forte 
1832*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
1833*fcf3ce44SJohn Forte 
1834*fcf3ce44SJohn Forte } /* emlxs_msi_uninit() */
1835*fcf3ce44SJohn Forte 
1836*fcf3ce44SJohn Forte 
1837*fcf3ce44SJohn Forte /* EMLXS_INTR_ADD */
1838*fcf3ce44SJohn Forte int32_t
1839*fcf3ce44SJohn Forte emlxs_msi_add(emlxs_hba_t *hba)
1840*fcf3ce44SJohn Forte {
1841*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1842*fcf3ce44SJohn Forte 	int32_t count;
1843*fcf3ce44SJohn Forte 	int32_t i;
1844*fcf3ce44SJohn Forte 	int32_t ret;
1845*fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable = NULL;
1846*fcf3ce44SJohn Forte 	int32_t *intr_cap = NULL;
1847*fcf3ce44SJohn Forte 
1848*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
1849*fcf3ce44SJohn Forte 		return (emlxs_intx_add(hba));
1850*fcf3ce44SJohn Forte 	}
1851*fcf3ce44SJohn Forte 	/* Check if interrupts have already been added */
1852*fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_MSI_ADDED) {
1853*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
1854*fcf3ce44SJohn Forte 	}
1855*fcf3ce44SJohn Forte 	/* Check if interrupts have been initialized */
1856*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
1857*fcf3ce44SJohn Forte 		ret = emlxs_msi_init(hba, 0);
1858*fcf3ce44SJohn Forte 
1859*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1860*fcf3ce44SJohn Forte 			return (ret);
1861*fcf3ce44SJohn Forte 		}
1862*fcf3ce44SJohn Forte 	}
1863*fcf3ce44SJohn Forte 	/* Get handle table parameters */
1864*fcf3ce44SJohn Forte 	htable = hba->intr_htable;
1865*fcf3ce44SJohn Forte 	count = hba->intr_count;
1866*fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
1867*fcf3ce44SJohn Forte 
1868*fcf3ce44SJohn Forte 	/* Add the interrupt handlers */
1869*fcf3ce44SJohn Forte 	for (i = 0; i < count; ++i) {
1870*fcf3ce44SJohn Forte 		/* add handler for handle[i] */
1871*fcf3ce44SJohn Forte 		ret = ddi_intr_add_handler(htable[i], emlxs_msi_intr,
1872*fcf3ce44SJohn Forte 		    (char *)hba, (char *)(unsigned long)i);
1873*fcf3ce44SJohn Forte 
1874*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1875*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1876*fcf3ce44SJohn Forte 			    "MSI: ddi_intr_add_handler(%d) failed. handle=%p "
1877*fcf3ce44SJohn Forte 			    "ret=%d", i, &htable[i], ret);
1878*fcf3ce44SJohn Forte 
1879*fcf3ce44SJohn Forte 			/* Process the remaining interrupt handlers */
1880*fcf3ce44SJohn Forte 			while (i) {
1881*fcf3ce44SJohn Forte 				/* Decrement i */
1882*fcf3ce44SJohn Forte 				i--;
1883*fcf3ce44SJohn Forte 
1884*fcf3ce44SJohn Forte 				/* Remove the handler */
1885*fcf3ce44SJohn Forte 				ret = ddi_intr_remove_handler(htable[i]);
1886*fcf3ce44SJohn Forte 
1887*fcf3ce44SJohn Forte 			}
1888*fcf3ce44SJohn Forte 
1889*fcf3ce44SJohn Forte 			return (DDI_FAILURE);
1890*fcf3ce44SJohn Forte 		}
1891*fcf3ce44SJohn Forte 	}
1892*fcf3ce44SJohn Forte 
1893*fcf3ce44SJohn Forte 	/* Enable the interrupts */
1894*fcf3ce44SJohn Forte 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
1895*fcf3ce44SJohn Forte 		ret = ddi_intr_block_enable(htable, count);
1896*fcf3ce44SJohn Forte 
1897*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1898*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1899*fcf3ce44SJohn Forte 			    "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
1900*fcf3ce44SJohn Forte 			    count, ret);
1901*fcf3ce44SJohn Forte 
1902*fcf3ce44SJohn Forte 			for (i = 0; i < count; ++i) {
1903*fcf3ce44SJohn Forte 				ret = ddi_intr_enable(htable[i]);
1904*fcf3ce44SJohn Forte 
1905*fcf3ce44SJohn Forte 				if (ret != DDI_SUCCESS) {
1906*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1907*fcf3ce44SJohn Forte 					    &emlxs_init_debug_msg,
1908*fcf3ce44SJohn Forte 					    "MSI: ddi_intr_enable(%d) failed. "
1909*fcf3ce44SJohn Forte 					    "ret=%d", i, ret);
1910*fcf3ce44SJohn Forte 				}
1911*fcf3ce44SJohn Forte 			}
1912*fcf3ce44SJohn Forte 		}
1913*fcf3ce44SJohn Forte 	} else {
1914*fcf3ce44SJohn Forte 		for (i = 0; i < count; ++i) {
1915*fcf3ce44SJohn Forte 			ret = ddi_intr_enable(htable[i]);
1916*fcf3ce44SJohn Forte 
1917*fcf3ce44SJohn Forte 			if (ret != DDI_SUCCESS) {
1918*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1919*fcf3ce44SJohn Forte 				    "MSI: ddi_intr_enable(%d) failed. ret=%d",
1920*fcf3ce44SJohn Forte 				    i, ret);
1921*fcf3ce44SJohn Forte 			}
1922*fcf3ce44SJohn Forte 		}
1923*fcf3ce44SJohn Forte 	}
1924*fcf3ce44SJohn Forte 
1925*fcf3ce44SJohn Forte 
1926*fcf3ce44SJohn Forte 	/* Set flag to indicate support */
1927*fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_MSI_ADDED;
1928*fcf3ce44SJohn Forte 
1929*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
1930*fcf3ce44SJohn Forte 
1931*fcf3ce44SJohn Forte } /* emlxs_msi_add() */
1932*fcf3ce44SJohn Forte 
1933*fcf3ce44SJohn Forte 
1934*fcf3ce44SJohn Forte 
1935*fcf3ce44SJohn Forte /* EMLXS_INTR_REMOVE */
1936*fcf3ce44SJohn Forte int32_t
1937*fcf3ce44SJohn Forte emlxs_msi_remove(emlxs_hba_t *hba)
1938*fcf3ce44SJohn Forte {
1939*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1940*fcf3ce44SJohn Forte 	uint32_t count;
1941*fcf3ce44SJohn Forte 	int32_t i;
1942*fcf3ce44SJohn Forte 	ddi_intr_handle_t *htable;
1943*fcf3ce44SJohn Forte 	int32_t *intr_cap;
1944*fcf3ce44SJohn Forte 	int32_t ret;
1945*fcf3ce44SJohn Forte 
1946*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
1947*fcf3ce44SJohn Forte 		return (emlxs_intx_remove(hba));
1948*fcf3ce44SJohn Forte 	}
1949*fcf3ce44SJohn Forte 	/*
1950*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "MSI:
1951*fcf3ce44SJohn Forte 	 * emlxs_msi_remove called. flags=%x", hba->intr_flags);
1952*fcf3ce44SJohn Forte 	 */
1953*fcf3ce44SJohn Forte 
1954*fcf3ce44SJohn Forte 	/* Check if interrupts have already been removed */
1955*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
1956*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
1957*fcf3ce44SJohn Forte 	}
1958*fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_MSI_ADDED;
1959*fcf3ce44SJohn Forte 
1960*fcf3ce44SJohn Forte 	/* Disable all adapter interrupts */
1961*fcf3ce44SJohn Forte 	hba->hc_copy = 0;
1962*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
1963*fcf3ce44SJohn Forte 
1964*fcf3ce44SJohn Forte 	/* Get handle table parameters */
1965*fcf3ce44SJohn Forte 	htable = hba->intr_htable;
1966*fcf3ce44SJohn Forte 	count = hba->intr_count;
1967*fcf3ce44SJohn Forte 	intr_cap = hba->intr_cap;
1968*fcf3ce44SJohn Forte 
1969*fcf3ce44SJohn Forte 	/* Disable the interrupts */
1970*fcf3ce44SJohn Forte 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
1971*fcf3ce44SJohn Forte 		ret = ddi_intr_block_disable(htable, count);
1972*fcf3ce44SJohn Forte 
1973*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
1974*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1975*fcf3ce44SJohn Forte 			    "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
1976*fcf3ce44SJohn Forte 			    count, ret);
1977*fcf3ce44SJohn Forte 
1978*fcf3ce44SJohn Forte 			for (i = 0; i < count; i++) {
1979*fcf3ce44SJohn Forte 				ret = ddi_intr_disable(htable[i]);
1980*fcf3ce44SJohn Forte 
1981*fcf3ce44SJohn Forte 				if (ret != DDI_SUCCESS) {
1982*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1983*fcf3ce44SJohn Forte 					    &emlxs_init_debug_msg,
1984*fcf3ce44SJohn Forte 					    "MSI: ddi_intr_disable(%d) failed. "
1985*fcf3ce44SJohn Forte 					    "ret=%d", i, ret);
1986*fcf3ce44SJohn Forte 				}
1987*fcf3ce44SJohn Forte 			}
1988*fcf3ce44SJohn Forte 		}
1989*fcf3ce44SJohn Forte 	} else {
1990*fcf3ce44SJohn Forte 		for (i = 0; i < count; i++) {
1991*fcf3ce44SJohn Forte 			ret = ddi_intr_disable(htable[i]);
1992*fcf3ce44SJohn Forte 
1993*fcf3ce44SJohn Forte 			if (ret != DDI_SUCCESS) {
1994*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1995*fcf3ce44SJohn Forte 				    "MSI: ddi_intr_disable(%d) failed. ret=%d",
1996*fcf3ce44SJohn Forte 				    i, ret);
1997*fcf3ce44SJohn Forte 			}
1998*fcf3ce44SJohn Forte 		}
1999*fcf3ce44SJohn Forte 	}
2000*fcf3ce44SJohn Forte 
2001*fcf3ce44SJohn Forte 	/* Process the interrupt handlers */
2002*fcf3ce44SJohn Forte 	for (i = 0; i < count; i++) {
2003*fcf3ce44SJohn Forte 		/* Remove the handler */
2004*fcf3ce44SJohn Forte 		ret = ddi_intr_remove_handler(htable[i]);
2005*fcf3ce44SJohn Forte 
2006*fcf3ce44SJohn Forte 
2007*fcf3ce44SJohn Forte 	}
2008*fcf3ce44SJohn Forte 
2009*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
2010*fcf3ce44SJohn Forte 
2011*fcf3ce44SJohn Forte } /* emlxs_msi_remove() */
2012*fcf3ce44SJohn Forte 
2013*fcf3ce44SJohn Forte 
2014*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
2015*fcf3ce44SJohn Forte 
2016*fcf3ce44SJohn Forte 
2017*fcf3ce44SJohn Forte /* EMLXS_INTR_INIT */
2018*fcf3ce44SJohn Forte /* ARGSUSED */
2019*fcf3ce44SJohn Forte int32_t
2020*fcf3ce44SJohn Forte emlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
2021*fcf3ce44SJohn Forte {
2022*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2023*fcf3ce44SJohn Forte 	int32_t ret;
2024*fcf3ce44SJohn Forte 	uint32_t i;
2025*fcf3ce44SJohn Forte 	char buf[64];
2026*fcf3ce44SJohn Forte 
2027*fcf3ce44SJohn Forte 	/* Check if interrupts have already been initialized */
2028*fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_INTX_INITED) {
2029*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
2030*fcf3ce44SJohn Forte 	}
2031*fcf3ce44SJohn Forte 	/* Check if adapter is flagged for INTX support */
2032*fcf3ce44SJohn Forte 	if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
2033*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2034*fcf3ce44SJohn Forte 		    "INTX: %s does not support INTX.  flags=0x%x",
2035*fcf3ce44SJohn Forte 		    hba->model_info.model, hba->model_info.flags);
2036*fcf3ce44SJohn Forte 
2037*fcf3ce44SJohn Forte 		return (DDI_FAILURE);
2038*fcf3ce44SJohn Forte 	}
2039*fcf3ce44SJohn Forte 	/*
2040*fcf3ce44SJohn Forte 	 * Interrupt number '0' is a high-level interrupt. This driver does
2041*fcf3ce44SJohn Forte 	 * not support having its interrupts mapped above scheduler priority;
2042*fcf3ce44SJohn Forte 	 * i.e., we always expect to be able to call general kernel routines
2043*fcf3ce44SJohn Forte 	 * that may invoke the scheduler.
2044*fcf3ce44SJohn Forte 	 */
2045*fcf3ce44SJohn Forte 	if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
2046*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2047*fcf3ce44SJohn Forte 		    "INTX: High-level interrupt not supported.");
2048*fcf3ce44SJohn Forte 
2049*fcf3ce44SJohn Forte 		return (DDI_FAILURE);
2050*fcf3ce44SJohn Forte 	}
2051*fcf3ce44SJohn Forte 	/* Get an iblock cookie */
2052*fcf3ce44SJohn Forte 	ret = ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
2053*fcf3ce44SJohn Forte 	    (ddi_iblock_cookie_t *)&hba->intr_arg);
2054*fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
2055*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2056*fcf3ce44SJohn Forte 		    "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
2057*fcf3ce44SJohn Forte 
2058*fcf3ce44SJohn Forte 		return (ret);
2059*fcf3ce44SJohn Forte 	}
2060*fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_INTX_INITED;
2061*fcf3ce44SJohn Forte 
2062*fcf3ce44SJohn Forte 	/* Create the interrupt threads */
2063*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_RINGS; i++) {
2064*fcf3ce44SJohn Forte 		(void) sprintf(buf, "%s%d_ring%d mutex", DRIVER_NAME,
2065*fcf3ce44SJohn Forte 		    hba->ddiinst, i);
2066*fcf3ce44SJohn Forte 		mutex_init(&hba->ring[i].rsp_lock, buf, MUTEX_DRIVER,
2067*fcf3ce44SJohn Forte 		    (void *)hba->intr_arg);
2068*fcf3ce44SJohn Forte 
2069*fcf3ce44SJohn Forte 		emlxs_thread_create(hba, &hba->ring[i].intr_thread);
2070*fcf3ce44SJohn Forte 	}
2071*fcf3ce44SJohn Forte 
2072*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
2073*fcf3ce44SJohn Forte 
2074*fcf3ce44SJohn Forte } /* emlxs_intx_init() */
2075*fcf3ce44SJohn Forte 
2076*fcf3ce44SJohn Forte 
2077*fcf3ce44SJohn Forte /* EMLXS_INTR_UNINIT */
2078*fcf3ce44SJohn Forte int32_t
2079*fcf3ce44SJohn Forte emlxs_intx_uninit(emlxs_hba_t *hba)
2080*fcf3ce44SJohn Forte {
2081*fcf3ce44SJohn Forte 	int32_t ret;
2082*fcf3ce44SJohn Forte 	uint32_t i;
2083*fcf3ce44SJohn Forte 
2084*fcf3ce44SJohn Forte 	/* Make sure interrupts have been removed */
2085*fcf3ce44SJohn Forte 	if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
2086*fcf3ce44SJohn Forte 		ret = emlxs_intx_remove(hba);
2087*fcf3ce44SJohn Forte 
2088*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
2089*fcf3ce44SJohn Forte 			return (ret);
2090*fcf3ce44SJohn Forte 		}
2091*fcf3ce44SJohn Forte 	}
2092*fcf3ce44SJohn Forte 	/* Check if the interrupts are still initialized */
2093*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
2094*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
2095*fcf3ce44SJohn Forte 	}
2096*fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_INTX_INITED;
2097*fcf3ce44SJohn Forte 
2098*fcf3ce44SJohn Forte 	hba->intr_arg = NULL;
2099*fcf3ce44SJohn Forte 
2100*fcf3ce44SJohn Forte 	/* Create the interrupt threads */
2101*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_RINGS; i++) {
2102*fcf3ce44SJohn Forte 		emlxs_thread_destroy(&hba->ring[i].intr_thread);
2103*fcf3ce44SJohn Forte 		mutex_destroy(&hba->ring[i].rsp_lock);
2104*fcf3ce44SJohn Forte 	}
2105*fcf3ce44SJohn Forte 
2106*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
2107*fcf3ce44SJohn Forte 
2108*fcf3ce44SJohn Forte } /* emlxs_intx_uninit() */
2109*fcf3ce44SJohn Forte 
2110*fcf3ce44SJohn Forte 
2111*fcf3ce44SJohn Forte /* This is the legacy method for adding interrupts in Solaris */
2112*fcf3ce44SJohn Forte /* EMLXS_INTR_ADD */
2113*fcf3ce44SJohn Forte int32_t
2114*fcf3ce44SJohn Forte emlxs_intx_add(emlxs_hba_t *hba)
2115*fcf3ce44SJohn Forte {
2116*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2117*fcf3ce44SJohn Forte 	int32_t ret;
2118*fcf3ce44SJohn Forte 
2119*fcf3ce44SJohn Forte 	/* Check if interrupts have already been added */
2120*fcf3ce44SJohn Forte 	if (hba->intr_flags & EMLXS_INTX_ADDED) {
2121*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
2122*fcf3ce44SJohn Forte 	}
2123*fcf3ce44SJohn Forte 	/* Check if interrupts have been initialized */
2124*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
2125*fcf3ce44SJohn Forte 		ret = emlxs_intx_init(hba, 0);
2126*fcf3ce44SJohn Forte 
2127*fcf3ce44SJohn Forte 		if (ret != DDI_SUCCESS) {
2128*fcf3ce44SJohn Forte 			return (ret);
2129*fcf3ce44SJohn Forte 		}
2130*fcf3ce44SJohn Forte 	}
2131*fcf3ce44SJohn Forte 	/* add intrrupt handler routine */
2132*fcf3ce44SJohn Forte 	ret = ddi_add_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
2133*fcf3ce44SJohn Forte 	    (ddi_iblock_cookie_t *)&hba->intr_arg, (ddi_idevice_cookie_t *)0,
2134*fcf3ce44SJohn Forte 	    (uint_t(*) ())emlxs_intx_intr, (caddr_t)hba);
2135*fcf3ce44SJohn Forte 
2136*fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
2137*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
2138*fcf3ce44SJohn Forte 		    "INTX: ddi_add_intr failed. ret=%d", ret);
2139*fcf3ce44SJohn Forte 
2140*fcf3ce44SJohn Forte 		return (ret);
2141*fcf3ce44SJohn Forte 	}
2142*fcf3ce44SJohn Forte 	hba->intr_flags |= EMLXS_INTX_ADDED;
2143*fcf3ce44SJohn Forte 
2144*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
2145*fcf3ce44SJohn Forte 
2146*fcf3ce44SJohn Forte } /* emlxs_intx_add() */
2147*fcf3ce44SJohn Forte 
2148*fcf3ce44SJohn Forte 
2149*fcf3ce44SJohn Forte /* EMLXS_INTR_REMOVE */
2150*fcf3ce44SJohn Forte int32_t
2151*fcf3ce44SJohn Forte emlxs_intx_remove(emlxs_hba_t *hba)
2152*fcf3ce44SJohn Forte {
2153*fcf3ce44SJohn Forte 
2154*fcf3ce44SJohn Forte 	/* Check if interrupts have already been removed */
2155*fcf3ce44SJohn Forte 	if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
2156*fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
2157*fcf3ce44SJohn Forte 	}
2158*fcf3ce44SJohn Forte 	hba->intr_flags &= ~EMLXS_INTX_ADDED;
2159*fcf3ce44SJohn Forte 
2160*fcf3ce44SJohn Forte 	/* Diable all adapter interrupts */
2161*fcf3ce44SJohn Forte 	hba->hc_copy = 0;
2162*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
2163*fcf3ce44SJohn Forte 
2164*fcf3ce44SJohn Forte 	/* Remove the interrupt */
2165*fcf3ce44SJohn Forte 	(void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
2166*fcf3ce44SJohn Forte 	    hba->intr_arg);
2167*fcf3ce44SJohn Forte 
2168*fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
2169*fcf3ce44SJohn Forte 
2170*fcf3ce44SJohn Forte } /* emlxs_intx_remove() */
2171*fcf3ce44SJohn Forte 
2172*fcf3ce44SJohn Forte 
2173*fcf3ce44SJohn Forte extern int
2174*fcf3ce44SJohn Forte emlxs_hba_init(emlxs_hba_t *hba)
2175*fcf3ce44SJohn Forte {
2176*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2177*fcf3ce44SJohn Forte 	emlxs_port_t *vport;
2178*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
2179*fcf3ce44SJohn Forte 	int32_t i;
2180*fcf3ce44SJohn Forte 
2181*fcf3ce44SJohn Forte 	cfg = &CFG;
2182*fcf3ce44SJohn Forte 	i = 0;
2183*fcf3ce44SJohn Forte 
2184*fcf3ce44SJohn Forte 	/* Restart the adapter */
2185*fcf3ce44SJohn Forte 	if (emlxs_hba_reset(hba, 1, 0)) {
2186*fcf3ce44SJohn Forte 		return (1);
2187*fcf3ce44SJohn Forte 	}
2188*fcf3ce44SJohn Forte 	hba->ring_count = MAX_RINGS;	/* number of rings used */
2189*fcf3ce44SJohn Forte 
2190*fcf3ce44SJohn Forte 	/* WARNING: There is a max of 6 ring masks allowed */
2191*fcf3ce44SJohn Forte 	/*
2192*fcf3ce44SJohn Forte 	 * RING 0 - FCP
2193*fcf3ce44SJohn Forte 	 */
2194*fcf3ce44SJohn Forte 	if (hba->tgt_mode) {
2195*fcf3ce44SJohn Forte 		hba->ring_masks[FC_FCP_RING] = 1;
2196*fcf3ce44SJohn Forte 		hba->ring_rval[i] = FC_FCP_CMND;
2197*fcf3ce44SJohn Forte 		hba->ring_rmask[i] = 0;
2198*fcf3ce44SJohn Forte 		hba->ring_tval[i] = FC_FCP_DATA;
2199*fcf3ce44SJohn Forte 		hba->ring_tmask[i++] = 0xFF;
2200*fcf3ce44SJohn Forte 	} else {
2201*fcf3ce44SJohn Forte 		hba->ring_masks[FC_FCP_RING] = 0;
2202*fcf3ce44SJohn Forte 	}
2203*fcf3ce44SJohn Forte 
2204*fcf3ce44SJohn Forte 	hba->ring[FC_FCP_RING].fc_numCiocb = SLIM_IOCB_CMD_R0_ENTRIES;
2205*fcf3ce44SJohn Forte 	hba->ring[FC_FCP_RING].fc_numRiocb = SLIM_IOCB_RSP_R0_ENTRIES;
2206*fcf3ce44SJohn Forte 
2207*fcf3ce44SJohn Forte 	/*
2208*fcf3ce44SJohn Forte 	 * RING 1 - IP
2209*fcf3ce44SJohn Forte 	 */
2210*fcf3ce44SJohn Forte 	if (cfg[CFG_NETWORK_ON].current) {
2211*fcf3ce44SJohn Forte 		hba->ring_masks[FC_IP_RING] = 1;
2212*fcf3ce44SJohn Forte 		hba->ring_rval[i] = FC_UNSOL_DATA;	/* Unsolicited Data */
2213*fcf3ce44SJohn Forte 		hba->ring_rmask[i] = 0xFF;
2214*fcf3ce44SJohn Forte 		hba->ring_tval[i] = FC_LLC_SNAP;	/* LLC/SNAP */
2215*fcf3ce44SJohn Forte 		hba->ring_tmask[i++] = 0xFF;
2216*fcf3ce44SJohn Forte 	} else {
2217*fcf3ce44SJohn Forte 		hba->ring_masks[FC_IP_RING] = 0;
2218*fcf3ce44SJohn Forte 	}
2219*fcf3ce44SJohn Forte 
2220*fcf3ce44SJohn Forte 	hba->ring[FC_IP_RING].fc_numCiocb = SLIM_IOCB_CMD_R1_ENTRIES;
2221*fcf3ce44SJohn Forte 	hba->ring[FC_IP_RING].fc_numRiocb = SLIM_IOCB_RSP_R1_ENTRIES;
2222*fcf3ce44SJohn Forte 
2223*fcf3ce44SJohn Forte 	/*
2224*fcf3ce44SJohn Forte 	 * RING 2 - ELS
2225*fcf3ce44SJohn Forte 	 */
2226*fcf3ce44SJohn Forte 	hba->ring_masks[FC_ELS_RING] = 1;
2227*fcf3ce44SJohn Forte 	hba->ring_rval[i] = FC_ELS_REQ;	/* ELS request/response */
2228*fcf3ce44SJohn Forte 	hba->ring_rmask[i] = 0xFE;
2229*fcf3ce44SJohn Forte 	hba->ring_tval[i] = FC_ELS_DATA;	/* ELS */
2230*fcf3ce44SJohn Forte 	hba->ring_tmask[i++] = 0xFF;
2231*fcf3ce44SJohn Forte 
2232*fcf3ce44SJohn Forte 	hba->ring[FC_ELS_RING].fc_numCiocb = SLIM_IOCB_CMD_R2_ENTRIES;
2233*fcf3ce44SJohn Forte 	hba->ring[FC_ELS_RING].fc_numRiocb = SLIM_IOCB_RSP_R2_ENTRIES;
2234*fcf3ce44SJohn Forte 
2235*fcf3ce44SJohn Forte 	/*
2236*fcf3ce44SJohn Forte 	 * RING 3 - CT
2237*fcf3ce44SJohn Forte 	 */
2238*fcf3ce44SJohn Forte 	hba->ring_masks[FC_CT_RING] = 1;
2239*fcf3ce44SJohn Forte 	hba->ring_rval[i] = FC_UNSOL_CTL;	/* CT request/response */
2240*fcf3ce44SJohn Forte 	hba->ring_rmask[i] = 0xFE;
2241*fcf3ce44SJohn Forte 	hba->ring_tval[i] = FC_CT_TYPE;	/* CT */
2242*fcf3ce44SJohn Forte 	hba->ring_tmask[i++] = 0xFF;
2243*fcf3ce44SJohn Forte 
2244*fcf3ce44SJohn Forte 	hba->ring[FC_CT_RING].fc_numCiocb = SLIM_IOCB_CMD_R3_ENTRIES;
2245*fcf3ce44SJohn Forte 	hba->ring[FC_CT_RING].fc_numRiocb = SLIM_IOCB_RSP_R3_ENTRIES;
2246*fcf3ce44SJohn Forte 
2247*fcf3ce44SJohn Forte 	if (i > 6) {
2248*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
2249*fcf3ce44SJohn Forte 		    "emlxs_hba_init: Too many ring masks defined. cnt=%d", i);
2250*fcf3ce44SJohn Forte 		return (1);
2251*fcf3ce44SJohn Forte 	}
2252*fcf3ce44SJohn Forte 	/* Initialize all the port objects */
2253*fcf3ce44SJohn Forte 	hba->vpi_max = 1;
2254*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
2255*fcf3ce44SJohn Forte 		vport = &VPORT(i);
2256*fcf3ce44SJohn Forte 		vport->hba = hba;
2257*fcf3ce44SJohn Forte 		vport->vpi = i;
2258*fcf3ce44SJohn Forte 	}
2259*fcf3ce44SJohn Forte 
2260*fcf3ce44SJohn Forte 	/*
2261*fcf3ce44SJohn Forte 	 * Initialize the max_node count to a default value if needed
2262*fcf3ce44SJohn Forte 	 * This determines how many node objects we preallocate in the pool
2263*fcf3ce44SJohn Forte 	 * The actual max_nodes will be set later based on adapter info
2264*fcf3ce44SJohn Forte 	 */
2265*fcf3ce44SJohn Forte 	if (hba->max_nodes == 0) {
2266*fcf3ce44SJohn Forte 		if (cfg[CFG_NUM_NODES].current > 0) {
2267*fcf3ce44SJohn Forte 			hba->max_nodes = cfg[CFG_NUM_NODES].current;
2268*fcf3ce44SJohn Forte 		} else if (hba->model_info.chip >= EMLXS_SATURN_CHIP) {
2269*fcf3ce44SJohn Forte 			hba->max_nodes = 4096;
2270*fcf3ce44SJohn Forte 		} else {
2271*fcf3ce44SJohn Forte 			hba->max_nodes = 512;
2272*fcf3ce44SJohn Forte 		}
2273*fcf3ce44SJohn Forte 	}
2274*fcf3ce44SJohn Forte 	return (0);
2275*fcf3ce44SJohn Forte 
2276*fcf3ce44SJohn Forte } /* emlxs_hba_init() */
2277*fcf3ce44SJohn Forte 
2278*fcf3ce44SJohn Forte 
2279*fcf3ce44SJohn Forte static void
2280*fcf3ce44SJohn Forte emlxs_process_link_speed(emlxs_hba_t *hba)
2281*fcf3ce44SJohn Forte {
2282*fcf3ce44SJohn Forte 	emlxs_vpd_t *vpd;
2283*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
2284*fcf3ce44SJohn Forte 	char *cptr;
2285*fcf3ce44SJohn Forte 	uint32_t hi;
2286*fcf3ce44SJohn Forte 
2287*fcf3ce44SJohn Forte 	/*
2288*fcf3ce44SJohn Forte 	 * This routine modifies the link-speed config parameter entry based
2289*fcf3ce44SJohn Forte 	 * on adapter capabilities
2290*fcf3ce44SJohn Forte 	 */
2291*fcf3ce44SJohn Forte 	vpd = &VPD;
2292*fcf3ce44SJohn Forte 	cfg = &hba->config[CFG_LINK_SPEED];
2293*fcf3ce44SJohn Forte 
2294*fcf3ce44SJohn Forte 	cptr = cfg->help;
2295*fcf3ce44SJohn Forte 	(void) strcpy(cptr, "Select link speed. [0=Auto");
2296*fcf3ce44SJohn Forte 	cptr += 26;
2297*fcf3ce44SJohn Forte 	hi = 0;
2298*fcf3ce44SJohn Forte 
2299*fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
2300*fcf3ce44SJohn Forte 		(void) strcpy(cptr, ", 1=1Gb");
2301*fcf3ce44SJohn Forte 		cptr += 7;
2302*fcf3ce44SJohn Forte 		hi = 1;
2303*fcf3ce44SJohn Forte 	}
2304*fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
2305*fcf3ce44SJohn Forte 		(void) strcpy(cptr, ", 2=2Gb");
2306*fcf3ce44SJohn Forte 		cptr += 7;
2307*fcf3ce44SJohn Forte 		hi = 2;
2308*fcf3ce44SJohn Forte 	}
2309*fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
2310*fcf3ce44SJohn Forte 		(void) strcpy(cptr, ", 4=4Gb");
2311*fcf3ce44SJohn Forte 		cptr += 7;
2312*fcf3ce44SJohn Forte 		hi = 4;
2313*fcf3ce44SJohn Forte 	}
2314*fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
2315*fcf3ce44SJohn Forte 		(void) strcpy(cptr, ", 8=8Gb");
2316*fcf3ce44SJohn Forte 		cptr += 7;
2317*fcf3ce44SJohn Forte 		hi = 8;
2318*fcf3ce44SJohn Forte 	}
2319*fcf3ce44SJohn Forte 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
2320*fcf3ce44SJohn Forte 		(void) strcpy(cptr, ", 10=10Gb");
2321*fcf3ce44SJohn Forte 		cptr += 9;
2322*fcf3ce44SJohn Forte 		hi = 10;
2323*fcf3ce44SJohn Forte 	}
2324*fcf3ce44SJohn Forte 	(void) strcpy(cptr, "]");
2325*fcf3ce44SJohn Forte 	cfg->hi = hi;
2326*fcf3ce44SJohn Forte 
2327*fcf3ce44SJohn Forte 	/* Now revalidate the current parameter setting */
2328*fcf3ce44SJohn Forte 	cfg->current = emlxs_check_parm(hba, CFG_LINK_SPEED, cfg->current);
2329*fcf3ce44SJohn Forte 
2330*fcf3ce44SJohn Forte 	return;
2331*fcf3ce44SJohn Forte 
2332*fcf3ce44SJohn Forte } /* emlxs_process_link_speed() */
2333*fcf3ce44SJohn Forte 
2334*fcf3ce44SJohn Forte 
2335*fcf3ce44SJohn Forte /*
2336*fcf3ce44SJohn Forte  *
2337*fcf3ce44SJohn Forte  * emlxs_parse_vpd
2338*fcf3ce44SJohn Forte  * This routine will parse the VPD data
2339*fcf3ce44SJohn Forte  *
2340*fcf3ce44SJohn Forte  */
2341*fcf3ce44SJohn Forte extern int
2342*fcf3ce44SJohn Forte emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd_buf, uint32_t size)
2343*fcf3ce44SJohn Forte {
2344*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2345*fcf3ce44SJohn Forte 	char tag[3];
2346*fcf3ce44SJohn Forte 	uint8_t lenlo, lenhi;
2347*fcf3ce44SJohn Forte 	uint32_t n;
2348*fcf3ce44SJohn Forte 	uint16_t block_size;
2349*fcf3ce44SJohn Forte 	uint32_t block_index = 0;
2350*fcf3ce44SJohn Forte 	uint8_t sub_size;
2351*fcf3ce44SJohn Forte 	uint32_t sub_index;
2352*fcf3ce44SJohn Forte 	int32_t finished = 0;
2353*fcf3ce44SJohn Forte 	int32_t index = 0;
2354*fcf3ce44SJohn Forte 	char buffer[128];
2355*fcf3ce44SJohn Forte 	emlxs_vpd_t *vpd;
2356*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
2357*fcf3ce44SJohn Forte 
2358*fcf3ce44SJohn Forte 	vpd = &VPD;
2359*fcf3ce44SJohn Forte 	cfg = &CFG;
2360*fcf3ce44SJohn Forte 
2361*fcf3ce44SJohn Forte #ifdef MENLO_TEST
2362*fcf3ce44SJohn Forte 	/* Check if VPD is disabled Hornet adapters */
2363*fcf3ce44SJohn Forte 	if ((hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) &&
2364*fcf3ce44SJohn Forte 	    (cfg[CFG_HORNET_VPD].current == 0)) {
2365*fcf3ce44SJohn Forte 		return (1);
2366*fcf3ce44SJohn Forte 	}
2367*fcf3ce44SJohn Forte #endif	/* MENLO_TEST */
2368*fcf3ce44SJohn Forte 
2369*fcf3ce44SJohn Forte 
2370*fcf3ce44SJohn Forte 	while (!finished && (block_index < size)) {
2371*fcf3ce44SJohn Forte 		/*
2372*fcf3ce44SJohn Forte 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "block_index =
2373*fcf3ce44SJohn Forte 		 * %x", block_index);
2374*fcf3ce44SJohn Forte 		 */
2375*fcf3ce44SJohn Forte 
2376*fcf3ce44SJohn Forte 		switch (vpd_buf[block_index]) {
2377*fcf3ce44SJohn Forte 		case 0x82:
2378*fcf3ce44SJohn Forte 			index = block_index;
2379*fcf3ce44SJohn Forte 			index += 1;
2380*fcf3ce44SJohn Forte 			lenlo = vpd_buf[index];
2381*fcf3ce44SJohn Forte 			index += 1;
2382*fcf3ce44SJohn Forte 			lenhi = vpd_buf[index];
2383*fcf3ce44SJohn Forte 			index += 1;
2384*fcf3ce44SJohn Forte 			block_index = index;
2385*fcf3ce44SJohn Forte 
2386*fcf3ce44SJohn Forte 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
2387*fcf3ce44SJohn Forte 			block_index += block_size;
2388*fcf3ce44SJohn Forte 
2389*fcf3ce44SJohn Forte 			/*
2390*fcf3ce44SJohn Forte 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2391*fcf3ce44SJohn Forte 			 * "block_size = %x", block_size);
2392*fcf3ce44SJohn Forte 			 */
2393*fcf3ce44SJohn Forte 
2394*fcf3ce44SJohn Forte 			n = sizeof (buffer);
2395*fcf3ce44SJohn Forte 			bzero(buffer, n);
2396*fcf3ce44SJohn Forte 			bcopy(&vpd_buf[index], buffer,
2397*fcf3ce44SJohn Forte 			    (block_size < (n - 1)) ? block_size : (n - 1));
2398*fcf3ce44SJohn Forte 
2399*fcf3ce44SJohn Forte 			(void) strcpy(vpd->id, buffer);
2400*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2401*fcf3ce44SJohn Forte 			    "ID: %s", vpd->id);
2402*fcf3ce44SJohn Forte 
2403*fcf3ce44SJohn Forte 			break;
2404*fcf3ce44SJohn Forte 
2405*fcf3ce44SJohn Forte 		case 0x90:
2406*fcf3ce44SJohn Forte 			index = block_index;
2407*fcf3ce44SJohn Forte 			index += 1;
2408*fcf3ce44SJohn Forte 			lenlo = vpd_buf[index];
2409*fcf3ce44SJohn Forte 			index += 1;
2410*fcf3ce44SJohn Forte 			lenhi = vpd_buf[index];
2411*fcf3ce44SJohn Forte 			index += 1;
2412*fcf3ce44SJohn Forte 			block_index = index;
2413*fcf3ce44SJohn Forte 			sub_index = index;
2414*fcf3ce44SJohn Forte 
2415*fcf3ce44SJohn Forte 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
2416*fcf3ce44SJohn Forte 			block_index += block_size;
2417*fcf3ce44SJohn Forte 
2418*fcf3ce44SJohn Forte 			/*
2419*fcf3ce44SJohn Forte 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2420*fcf3ce44SJohn Forte 			 * "block_size = %x", block_size);
2421*fcf3ce44SJohn Forte 			 */
2422*fcf3ce44SJohn Forte 
2423*fcf3ce44SJohn Forte 			/* Scan for sub-blocks */
2424*fcf3ce44SJohn Forte 			while ((sub_index < block_index) &&
2425*fcf3ce44SJohn Forte 			    (sub_index < size)) {
2426*fcf3ce44SJohn Forte 				/*
2427*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2428*fcf3ce44SJohn Forte 				 * "sub_index = %x", sub_index);
2429*fcf3ce44SJohn Forte 				 */
2430*fcf3ce44SJohn Forte 
2431*fcf3ce44SJohn Forte 				index = sub_index;
2432*fcf3ce44SJohn Forte 				tag[0] = vpd_buf[index++];
2433*fcf3ce44SJohn Forte 				tag[1] = vpd_buf[index++];
2434*fcf3ce44SJohn Forte 				tag[2] = 0;
2435*fcf3ce44SJohn Forte 				sub_size = vpd_buf[index++];
2436*fcf3ce44SJohn Forte 
2437*fcf3ce44SJohn Forte 				/*
2438*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2439*fcf3ce44SJohn Forte 				 * "sub_size = %x", sub_size);
2440*fcf3ce44SJohn Forte 				 */
2441*fcf3ce44SJohn Forte 
2442*fcf3ce44SJohn Forte 				sub_index = (index + sub_size);
2443*fcf3ce44SJohn Forte 
2444*fcf3ce44SJohn Forte 				n = sizeof (buffer);
2445*fcf3ce44SJohn Forte 				bzero(buffer, n);
2446*fcf3ce44SJohn Forte 				bcopy(&vpd_buf[index], buffer,
2447*fcf3ce44SJohn Forte 				    (sub_size < (n - 1)) ? sub_size : (n - 1));
2448*fcf3ce44SJohn Forte 
2449*fcf3ce44SJohn Forte 				/*
2450*fcf3ce44SJohn Forte 				 * Look for Engineering Change (EC)
2451*fcf3ce44SJohn Forte 				 */
2452*fcf3ce44SJohn Forte 				if (strcmp(tag, "EC") == 0) {
2453*fcf3ce44SJohn Forte 					(void) strcpy(vpd->eng_change, buffer);
2454*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2455*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2456*fcf3ce44SJohn Forte 					    "EC: %s", vpd->eng_change);
2457*fcf3ce44SJohn Forte 				}
2458*fcf3ce44SJohn Forte 				/*
2459*fcf3ce44SJohn Forte 				 * Look for Manufacturer (MN)
2460*fcf3ce44SJohn Forte 				 */
2461*fcf3ce44SJohn Forte 				else if (strcmp(tag, "MN") == 0) {
2462*fcf3ce44SJohn Forte 					(void) strcpy(vpd->manufacturer,
2463*fcf3ce44SJohn Forte 					    buffer);
2464*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2465*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2466*fcf3ce44SJohn Forte 					    "MN: %s", vpd->manufacturer);
2467*fcf3ce44SJohn Forte 				}
2468*fcf3ce44SJohn Forte 				/*
2469*fcf3ce44SJohn Forte 				 * Look for Serial Number (SN)
2470*fcf3ce44SJohn Forte 				 */
2471*fcf3ce44SJohn Forte 				else if (strcmp(tag, "SN") == 0) {
2472*fcf3ce44SJohn Forte 					(void) strcpy(vpd->serial_num, buffer);
2473*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2474*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2475*fcf3ce44SJohn Forte 					    "SN: %s", vpd->serial_num);
2476*fcf3ce44SJohn Forte 
2477*fcf3ce44SJohn Forte 					/* Validate the serial number */
2478*fcf3ce44SJohn Forte 					if ((strncmp(buffer, "FFFFFFFFFF",
2479*fcf3ce44SJohn Forte 					    10) == 0) ||
2480*fcf3ce44SJohn Forte 					    (strncmp(buffer, "0000000000",
2481*fcf3ce44SJohn Forte 					    10) == 0)) {
2482*fcf3ce44SJohn Forte 						vpd->serial_num[0] = 0;
2483*fcf3ce44SJohn Forte 					}
2484*fcf3ce44SJohn Forte 				}
2485*fcf3ce44SJohn Forte 				/*
2486*fcf3ce44SJohn Forte 				 * Look for Part Number (PN)
2487*fcf3ce44SJohn Forte 				 */
2488*fcf3ce44SJohn Forte 				else if (strcmp(tag, "PN") == 0) {
2489*fcf3ce44SJohn Forte 					(void) strcpy(vpd->part_num, buffer);
2490*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2491*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2492*fcf3ce44SJohn Forte 					    "PN: %s", vpd->part_num);
2493*fcf3ce44SJohn Forte 				}
2494*fcf3ce44SJohn Forte 				/*
2495*fcf3ce44SJohn Forte 				 * Look for (V0)
2496*fcf3ce44SJohn Forte 				 */
2497*fcf3ce44SJohn Forte 				else if (strcmp(tag, "V0") == 0) {
2498*fcf3ce44SJohn Forte 					/* Not used */
2499*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2500*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2501*fcf3ce44SJohn Forte 					    "V0: %s", buffer);
2502*fcf3ce44SJohn Forte 				}
2503*fcf3ce44SJohn Forte 				/*
2504*fcf3ce44SJohn Forte 				 * Look for model description (V1)
2505*fcf3ce44SJohn Forte 				 */
2506*fcf3ce44SJohn Forte 				else if (strcmp(tag, "V1") == 0) {
2507*fcf3ce44SJohn Forte 					(void) strcpy(vpd->model_desc, buffer);
2508*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2509*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2510*fcf3ce44SJohn Forte 					    "Desc: %s", vpd->model_desc);
2511*fcf3ce44SJohn Forte 				}
2512*fcf3ce44SJohn Forte 				/*
2513*fcf3ce44SJohn Forte 				 * Look for model (V2)
2514*fcf3ce44SJohn Forte 				 */
2515*fcf3ce44SJohn Forte 				else if (strcmp(tag, "V2") == 0) {
2516*fcf3ce44SJohn Forte 					(void) strcpy(vpd->model, buffer);
2517*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2518*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2519*fcf3ce44SJohn Forte 					    "Model: %s", vpd->model);
2520*fcf3ce44SJohn Forte 				}
2521*fcf3ce44SJohn Forte 				/*
2522*fcf3ce44SJohn Forte 				 * Look for program type (V3)
2523*fcf3ce44SJohn Forte 				 */
2524*fcf3ce44SJohn Forte 
2525*fcf3ce44SJohn Forte 				else if (strcmp(tag, "V3") == 0) {
2526*fcf3ce44SJohn Forte 					(void) strcpy(vpd->prog_types, buffer);
2527*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2528*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2529*fcf3ce44SJohn Forte 					    "Prog Types: %s", vpd->prog_types);
2530*fcf3ce44SJohn Forte 				}
2531*fcf3ce44SJohn Forte 				/*
2532*fcf3ce44SJohn Forte 				 * Look for port number (V4)
2533*fcf3ce44SJohn Forte 				 */
2534*fcf3ce44SJohn Forte 				else if (strcmp(tag, "V4") == 0) {
2535*fcf3ce44SJohn Forte 					(void) strcpy(vpd->port_num, buffer);
2536*fcf3ce44SJohn Forte 					vpd->port_index =
2537*fcf3ce44SJohn Forte 					    emlxs_strtol(vpd->port_num, 10);
2538*fcf3ce44SJohn Forte 
2539*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2540*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2541*fcf3ce44SJohn Forte 					    "Port: %s",
2542*fcf3ce44SJohn Forte 					    (vpd->port_num[0]) ?
2543*fcf3ce44SJohn Forte 					    vpd->port_num : "not applicable");
2544*fcf3ce44SJohn Forte 				}
2545*fcf3ce44SJohn Forte 				/*
2546*fcf3ce44SJohn Forte 				 * Look for checksum (RV)
2547*fcf3ce44SJohn Forte 				 */
2548*fcf3ce44SJohn Forte 				else if (strcmp(tag, "RV") == 0) {
2549*fcf3ce44SJohn Forte 					/* Not used */
2550*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2551*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2552*fcf3ce44SJohn Forte 					    "Checksum: 0x%x", buffer[0]);
2553*fcf3ce44SJohn Forte 				} else {
2554*fcf3ce44SJohn Forte 					/* Generic */
2555*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
2556*fcf3ce44SJohn Forte 					    &emlxs_vpd_msg,
2557*fcf3ce44SJohn Forte 					    "Tag: %s: %s", tag, buffer);
2558*fcf3ce44SJohn Forte 				}
2559*fcf3ce44SJohn Forte 			}
2560*fcf3ce44SJohn Forte 
2561*fcf3ce44SJohn Forte 			break;
2562*fcf3ce44SJohn Forte 
2563*fcf3ce44SJohn Forte 		case 0x78:
2564*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "End Tag.");
2565*fcf3ce44SJohn Forte 			finished = 1;
2566*fcf3ce44SJohn Forte 			break;
2567*fcf3ce44SJohn Forte 
2568*fcf3ce44SJohn Forte 		default:
2569*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2570*fcf3ce44SJohn Forte 			    "Unknown block: %x %x %x %x %x %x %x %x",
2571*fcf3ce44SJohn Forte 			    vpd_buf[index], vpd_buf[index + 1],
2572*fcf3ce44SJohn Forte 			    vpd_buf[index + 2], vpd_buf[index + 3],
2573*fcf3ce44SJohn Forte 			    vpd_buf[index + 4], vpd_buf[index + 5],
2574*fcf3ce44SJohn Forte 			    vpd_buf[index + 6], vpd_buf[index + 7]);
2575*fcf3ce44SJohn Forte 			return (0);
2576*fcf3ce44SJohn Forte 		}
2577*fcf3ce44SJohn Forte 	}
2578*fcf3ce44SJohn Forte 
2579*fcf3ce44SJohn Forte 	return (1);
2580*fcf3ce44SJohn Forte 
2581*fcf3ce44SJohn Forte } /* emlxs_parse_vpd */
2582*fcf3ce44SJohn Forte 
2583*fcf3ce44SJohn Forte 
2584*fcf3ce44SJohn Forte 
2585*fcf3ce44SJohn Forte static uint32_t
2586*fcf3ce44SJohn Forte emlxs_decode_biu_rev(uint32_t rev)
2587*fcf3ce44SJohn Forte {
2588*fcf3ce44SJohn Forte 	return (rev & 0xf);
2589*fcf3ce44SJohn Forte } /* End emlxs_decode_biu_rev */
2590*fcf3ce44SJohn Forte 
2591*fcf3ce44SJohn Forte 
2592*fcf3ce44SJohn Forte static uint32_t
2593*fcf3ce44SJohn Forte emlxs_decode_endec_rev(uint32_t rev)
2594*fcf3ce44SJohn Forte {
2595*fcf3ce44SJohn Forte 	return ((rev >> 28) & 0xf);
2596*fcf3ce44SJohn Forte } /* End emlxs_decode_endec_rev */
2597*fcf3ce44SJohn Forte 
2598*fcf3ce44SJohn Forte 
2599*fcf3ce44SJohn Forte extern void
2600*fcf3ce44SJohn Forte emlxs_decode_firmware_rev(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
2601*fcf3ce44SJohn Forte {
2602*fcf3ce44SJohn Forte 	if (vpd->rBit) {
2603*fcf3ce44SJohn Forte 		switch (hba->sli_mode) {
2604*fcf3ce44SJohn Forte 			case 4:
2605*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_version, vpd->sli4FwName);
2606*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_label, vpd->sli4FwLabel);
2607*fcf3ce44SJohn Forte 			break;
2608*fcf3ce44SJohn Forte 		case 3:
2609*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_version, vpd->sli3FwName);
2610*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_label, vpd->sli3FwLabel);
2611*fcf3ce44SJohn Forte 			break;
2612*fcf3ce44SJohn Forte 		case 2:
2613*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_version, vpd->sli2FwName);
2614*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_label, vpd->sli2FwLabel);
2615*fcf3ce44SJohn Forte 			break;
2616*fcf3ce44SJohn Forte 		case 1:
2617*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_version, vpd->sli1FwName);
2618*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_label, vpd->sli1FwLabel);
2619*fcf3ce44SJohn Forte 			break;
2620*fcf3ce44SJohn Forte 		default:
2621*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_version, "unknown");
2622*fcf3ce44SJohn Forte 			(void) strcpy(vpd->fw_label, vpd->fw_version);
2623*fcf3ce44SJohn Forte 		}
2624*fcf3ce44SJohn Forte 	} else {
2625*fcf3ce44SJohn Forte 		emlxs_decode_version(vpd->smFwRev, vpd->fw_version);
2626*fcf3ce44SJohn Forte 		(void) strcpy(vpd->fw_label, vpd->fw_version);
2627*fcf3ce44SJohn Forte 	}
2628*fcf3ce44SJohn Forte 
2629*fcf3ce44SJohn Forte 	return;
2630*fcf3ce44SJohn Forte 
2631*fcf3ce44SJohn Forte } /* emlxs_decode_firmware_rev() */
2632*fcf3ce44SJohn Forte 
2633*fcf3ce44SJohn Forte 
2634*fcf3ce44SJohn Forte 
2635*fcf3ce44SJohn Forte extern void
2636*fcf3ce44SJohn Forte emlxs_decode_version(uint32_t version, char *buffer)
2637*fcf3ce44SJohn Forte {
2638*fcf3ce44SJohn Forte 	uint32_t b1, b2, b3, b4;
2639*fcf3ce44SJohn Forte 	char c;
2640*fcf3ce44SJohn Forte 
2641*fcf3ce44SJohn Forte 	b1 = (version & 0x0000f000) >> 12;
2642*fcf3ce44SJohn Forte 	b2 = (version & 0x00000f00) >> 8;
2643*fcf3ce44SJohn Forte 	b3 = (version & 0x000000c0) >> 6;
2644*fcf3ce44SJohn Forte 	b4 = (version & 0x00000030) >> 4;
2645*fcf3ce44SJohn Forte 
2646*fcf3ce44SJohn Forte 	if (b1 == 0 && b2 == 0) {
2647*fcf3ce44SJohn Forte 		(void) sprintf(buffer, "none");
2648*fcf3ce44SJohn Forte 		return;
2649*fcf3ce44SJohn Forte 	}
2650*fcf3ce44SJohn Forte 	c = 0;
2651*fcf3ce44SJohn Forte 	switch (b4) {
2652*fcf3ce44SJohn Forte 	case 0:
2653*fcf3ce44SJohn Forte 		c = 'n';
2654*fcf3ce44SJohn Forte 		break;
2655*fcf3ce44SJohn Forte 	case 1:
2656*fcf3ce44SJohn Forte 		c = 'a';
2657*fcf3ce44SJohn Forte 		break;
2658*fcf3ce44SJohn Forte 	case 2:
2659*fcf3ce44SJohn Forte 		c = 'b';
2660*fcf3ce44SJohn Forte 		break;
2661*fcf3ce44SJohn Forte 	case 3:
2662*fcf3ce44SJohn Forte 		if ((version & 0x0000000f)) {
2663*fcf3ce44SJohn Forte 			c = 'x';
2664*fcf3ce44SJohn Forte 		}
2665*fcf3ce44SJohn Forte 		break;
2666*fcf3ce44SJohn Forte 
2667*fcf3ce44SJohn Forte 	}
2668*fcf3ce44SJohn Forte 	b4 = (version & 0x0000000f);
2669*fcf3ce44SJohn Forte 
2670*fcf3ce44SJohn Forte 	if (c == 0) {
2671*fcf3ce44SJohn Forte 		(void) sprintf(buffer, "%d.%d%d", b1, b2, b3);
2672*fcf3ce44SJohn Forte 	} else {
2673*fcf3ce44SJohn Forte 		(void) sprintf(buffer, "%d.%d%d%c%d", b1, b2, b3, c, b4);
2674*fcf3ce44SJohn Forte 	}
2675*fcf3ce44SJohn Forte 
2676*fcf3ce44SJohn Forte 	return;
2677*fcf3ce44SJohn Forte 
2678*fcf3ce44SJohn Forte } /* emlxs_decode_version() */
2679*fcf3ce44SJohn Forte 
2680*fcf3ce44SJohn Forte 
2681*fcf3ce44SJohn Forte static void
2682*fcf3ce44SJohn Forte emlxs_decode_label(char *label, char *buffer)
2683*fcf3ce44SJohn Forte {
2684*fcf3ce44SJohn Forte 	uint32_t i;
2685*fcf3ce44SJohn Forte 	char name[16];
2686*fcf3ce44SJohn Forte #ifdef EMLXS_LITTLE_ENDIAN
2687*fcf3ce44SJohn Forte 	uint32_t *wptr;
2688*fcf3ce44SJohn Forte 	uint32_t word;
2689*fcf3ce44SJohn Forte #endif	/* EMLXS_LITTLE_ENDIAN */
2690*fcf3ce44SJohn Forte 
2691*fcf3ce44SJohn Forte 	bcopy(label, name, 16);
2692*fcf3ce44SJohn Forte 
2693*fcf3ce44SJohn Forte #ifdef EMLXS_LITTLE_ENDIAN
2694*fcf3ce44SJohn Forte 	wptr = (uint32_t *)name;
2695*fcf3ce44SJohn Forte 	for (i = 0; i < 3; i++) {
2696*fcf3ce44SJohn Forte 		word = *wptr;
2697*fcf3ce44SJohn Forte 		word = SWAP_DATA32(word);
2698*fcf3ce44SJohn Forte 		*wptr++ = word;
2699*fcf3ce44SJohn Forte 	}
2700*fcf3ce44SJohn Forte #endif	/* EMLXS_LITTLE_ENDIAN */
2701*fcf3ce44SJohn Forte 
2702*fcf3ce44SJohn Forte 	for (i = 0; i < 16; i++) {
2703*fcf3ce44SJohn Forte 		if (name[i] == 0x20) {
2704*fcf3ce44SJohn Forte 			name[i] = 0;
2705*fcf3ce44SJohn Forte 		}
2706*fcf3ce44SJohn Forte 	}
2707*fcf3ce44SJohn Forte 
2708*fcf3ce44SJohn Forte 	(void) strcpy(buffer, name);
2709*fcf3ce44SJohn Forte 
2710*fcf3ce44SJohn Forte 	return;
2711*fcf3ce44SJohn Forte 
2712*fcf3ce44SJohn Forte } /* emlxs_decode_label() */
2713*fcf3ce44SJohn Forte 
2714*fcf3ce44SJohn Forte 
2715*fcf3ce44SJohn Forte extern uint32_t
2716*fcf3ce44SJohn Forte emlxs_strtol(char *str, uint32_t base)
2717*fcf3ce44SJohn Forte {
2718*fcf3ce44SJohn Forte 	uint32_t value = 0;
2719*fcf3ce44SJohn Forte 	char *ptr;
2720*fcf3ce44SJohn Forte 	uint32_t factor = 1;
2721*fcf3ce44SJohn Forte 	uint32_t digits;
2722*fcf3ce44SJohn Forte 
2723*fcf3ce44SJohn Forte 	if (*str == 0) {
2724*fcf3ce44SJohn Forte 		return (0);
2725*fcf3ce44SJohn Forte 	}
2726*fcf3ce44SJohn Forte 	if (base != 10 && base != 16) {
2727*fcf3ce44SJohn Forte 		return (0);
2728*fcf3ce44SJohn Forte 	}
2729*fcf3ce44SJohn Forte 	/* Get max digits of value */
2730*fcf3ce44SJohn Forte 	digits = (base == 10) ? 9 : 8;
2731*fcf3ce44SJohn Forte 
2732*fcf3ce44SJohn Forte 	/* Position pointer to end of string */
2733*fcf3ce44SJohn Forte 	ptr = str + strlen(str);
2734*fcf3ce44SJohn Forte 
2735*fcf3ce44SJohn Forte 	/* Process string backwards */
2736*fcf3ce44SJohn Forte 	while ((ptr-- > str) && digits) {
2737*fcf3ce44SJohn Forte 		/* check for base 10 numbers */
2738*fcf3ce44SJohn Forte 		if (*ptr >= '0' && *ptr <= '9') {
2739*fcf3ce44SJohn Forte 			value += ((uint32_t)(*ptr - '0')) * factor;
2740*fcf3ce44SJohn Forte 			factor *= base;
2741*fcf3ce44SJohn Forte 			digits--;
2742*fcf3ce44SJohn Forte 		} else if (base == 16) {
2743*fcf3ce44SJohn Forte 			/* Check for base 16 numbers */
2744*fcf3ce44SJohn Forte 			if (*ptr >= 'a' && *ptr <= 'f') {
2745*fcf3ce44SJohn Forte 				value += ((uint32_t)(*ptr - 'a') + 10) * factor;
2746*fcf3ce44SJohn Forte 				factor *= base;
2747*fcf3ce44SJohn Forte 				digits--;
2748*fcf3ce44SJohn Forte 			} else if (*ptr >= 'A' && *ptr <= 'F') {
2749*fcf3ce44SJohn Forte 				value += ((uint32_t)(*ptr - 'A') + 10) * factor;
2750*fcf3ce44SJohn Forte 				factor *= base;
2751*fcf3ce44SJohn Forte 				digits--;
2752*fcf3ce44SJohn Forte 			} else if (factor > 1) {
2753*fcf3ce44SJohn Forte 				break;
2754*fcf3ce44SJohn Forte 			}
2755*fcf3ce44SJohn Forte 		} else if (factor > 1) {
2756*fcf3ce44SJohn Forte 			break;
2757*fcf3ce44SJohn Forte 		}
2758*fcf3ce44SJohn Forte 	}
2759*fcf3ce44SJohn Forte 
2760*fcf3ce44SJohn Forte 	return (value);
2761*fcf3ce44SJohn Forte 
2762*fcf3ce44SJohn Forte } /* emlxs_strtol() */
2763*fcf3ce44SJohn Forte 
2764*fcf3ce44SJohn Forte 
2765*fcf3ce44SJohn Forte extern uint64_t
2766*fcf3ce44SJohn Forte emlxs_strtoll(char *str, uint32_t base)
2767*fcf3ce44SJohn Forte {
2768*fcf3ce44SJohn Forte 	uint64_t value = 0;
2769*fcf3ce44SJohn Forte 	char *ptr;
2770*fcf3ce44SJohn Forte 	uint32_t factor = 1;
2771*fcf3ce44SJohn Forte 	uint32_t digits;
2772*fcf3ce44SJohn Forte 
2773*fcf3ce44SJohn Forte 	if (*str == 0) {
2774*fcf3ce44SJohn Forte 		return (0);
2775*fcf3ce44SJohn Forte 	}
2776*fcf3ce44SJohn Forte 	if (base != 10 && base != 16) {
2777*fcf3ce44SJohn Forte 		return (0);
2778*fcf3ce44SJohn Forte 	}
2779*fcf3ce44SJohn Forte 	/* Get max digits of value */
2780*fcf3ce44SJohn Forte 	digits = (base == 10) ? 19 : 16;
2781*fcf3ce44SJohn Forte 
2782*fcf3ce44SJohn Forte 	/* Position pointer to end of string */
2783*fcf3ce44SJohn Forte 	ptr = str + strlen(str);
2784*fcf3ce44SJohn Forte 
2785*fcf3ce44SJohn Forte 	/* Process string backwards */
2786*fcf3ce44SJohn Forte 	while ((ptr-- > str) && digits) {
2787*fcf3ce44SJohn Forte 		/* check for base 10 numbers */
2788*fcf3ce44SJohn Forte 		if (*ptr >= '0' && *ptr <= '9') {
2789*fcf3ce44SJohn Forte 			value += ((uint32_t)(*ptr - '0')) * factor;
2790*fcf3ce44SJohn Forte 			factor *= base;
2791*fcf3ce44SJohn Forte 			digits--;
2792*fcf3ce44SJohn Forte 		} else if (base == 16) {
2793*fcf3ce44SJohn Forte 			/* Check for base 16 numbers */
2794*fcf3ce44SJohn Forte 			if (*ptr >= 'a' && *ptr <= 'f') {
2795*fcf3ce44SJohn Forte 				value += ((uint32_t)(*ptr - 'a') + 10) * factor;
2796*fcf3ce44SJohn Forte 				factor *= base;
2797*fcf3ce44SJohn Forte 				digits--;
2798*fcf3ce44SJohn Forte 			} else if (*ptr >= 'A' && *ptr <= 'F') {
2799*fcf3ce44SJohn Forte 				value += ((uint32_t)(*ptr - 'A') + 10) * factor;
2800*fcf3ce44SJohn Forte 				factor *= base;
2801*fcf3ce44SJohn Forte 				digits--;
2802*fcf3ce44SJohn Forte 			} else if (factor > 1) {
2803*fcf3ce44SJohn Forte 				break;
2804*fcf3ce44SJohn Forte 			}
2805*fcf3ce44SJohn Forte 		} else if (factor > 1) {
2806*fcf3ce44SJohn Forte 			break;
2807*fcf3ce44SJohn Forte 		}
2808*fcf3ce44SJohn Forte 	}
2809*fcf3ce44SJohn Forte 
2810*fcf3ce44SJohn Forte 	return (value);
2811*fcf3ce44SJohn Forte 
2812*fcf3ce44SJohn Forte } /* emlxs_strtoll() */
2813*fcf3ce44SJohn Forte 
2814*fcf3ce44SJohn Forte static void
2815*fcf3ce44SJohn Forte emlxs_parse_prog_types(emlxs_hba_t *hba, char *prog_types)
2816*fcf3ce44SJohn Forte {
2817*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2818*fcf3ce44SJohn Forte 	uint32_t i;
2819*fcf3ce44SJohn Forte 	char *ptr;
2820*fcf3ce44SJohn Forte 	emlxs_model_t *model;
2821*fcf3ce44SJohn Forte 	char types_buffer[256];
2822*fcf3ce44SJohn Forte 	char *types;
2823*fcf3ce44SJohn Forte 
2824*fcf3ce44SJohn Forte 	bcopy(prog_types, types_buffer, 256);
2825*fcf3ce44SJohn Forte 	types = types_buffer;
2826*fcf3ce44SJohn Forte 
2827*fcf3ce44SJohn Forte 	model = &hba->model_info;
2828*fcf3ce44SJohn Forte 
2829*fcf3ce44SJohn Forte 	while (*types) {
2830*fcf3ce44SJohn Forte 		if (strncmp(types, "T2:", 3) == 0) {
2831*fcf3ce44SJohn Forte 			bzero(model->pt_2, sizeof (model->pt_2));
2832*fcf3ce44SJohn Forte 			types += 3;
2833*fcf3ce44SJohn Forte 
2834*fcf3ce44SJohn Forte 			i = 0;
2835*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2836*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2837*fcf3ce44SJohn Forte 				ptr = types;
2838*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2839*fcf3ce44SJohn Forte 					ptr++;
2840*fcf3ce44SJohn Forte 				*ptr = 0;
2841*fcf3ce44SJohn Forte 
2842*fcf3ce44SJohn Forte 				/* Save the value */
2843*fcf3ce44SJohn Forte 				model->pt_2[i++] =
2844*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2845*fcf3ce44SJohn Forte 
2846*fcf3ce44SJohn Forte 				/*
2847*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2848*fcf3ce44SJohn Forte 				 * "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
2849*fcf3ce44SJohn Forte 				 */
2850*fcf3ce44SJohn Forte 
2851*fcf3ce44SJohn Forte 				/* Move the str pointer */
2852*fcf3ce44SJohn Forte 				types = ptr + 1;
2853*fcf3ce44SJohn Forte 			}
2854*fcf3ce44SJohn Forte 
2855*fcf3ce44SJohn Forte 		} else if (strncmp(types, "T3:", 3) == 0) {
2856*fcf3ce44SJohn Forte 			bzero(model->pt_3, sizeof (model->pt_3));
2857*fcf3ce44SJohn Forte 			types += 3;
2858*fcf3ce44SJohn Forte 
2859*fcf3ce44SJohn Forte 			i = 0;
2860*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2861*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2862*fcf3ce44SJohn Forte 				ptr = types;
2863*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2864*fcf3ce44SJohn Forte 					ptr++;
2865*fcf3ce44SJohn Forte 				*ptr = 0;
2866*fcf3ce44SJohn Forte 
2867*fcf3ce44SJohn Forte 				/* Save the value */
2868*fcf3ce44SJohn Forte 				model->pt_3[i++] =
2869*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2870*fcf3ce44SJohn Forte 
2871*fcf3ce44SJohn Forte 				/*
2872*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2873*fcf3ce44SJohn Forte 				 * "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
2874*fcf3ce44SJohn Forte 				 */
2875*fcf3ce44SJohn Forte 
2876*fcf3ce44SJohn Forte 				/* Move the str pointer */
2877*fcf3ce44SJohn Forte 				types = ptr + 1;
2878*fcf3ce44SJohn Forte 			}
2879*fcf3ce44SJohn Forte 		} else if (strncmp(types, "T6:", 3) == 0) {
2880*fcf3ce44SJohn Forte 			bzero(model->pt_6, sizeof (model->pt_6));
2881*fcf3ce44SJohn Forte 			types += 3;
2882*fcf3ce44SJohn Forte 
2883*fcf3ce44SJohn Forte 			i = 0;
2884*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2885*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2886*fcf3ce44SJohn Forte 				ptr = types;
2887*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2888*fcf3ce44SJohn Forte 					ptr++;
2889*fcf3ce44SJohn Forte 				*ptr = 0;
2890*fcf3ce44SJohn Forte 
2891*fcf3ce44SJohn Forte 				/* Save the value */
2892*fcf3ce44SJohn Forte 				model->pt_6[i++] =
2893*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2894*fcf3ce44SJohn Forte 				model->pt_6[i] = 0;
2895*fcf3ce44SJohn Forte 
2896*fcf3ce44SJohn Forte 				/*
2897*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2898*fcf3ce44SJohn Forte 				 * "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
2899*fcf3ce44SJohn Forte 				 */
2900*fcf3ce44SJohn Forte 
2901*fcf3ce44SJohn Forte 				/* Move the str pointer */
2902*fcf3ce44SJohn Forte 				types = ptr + 1;
2903*fcf3ce44SJohn Forte 			}
2904*fcf3ce44SJohn Forte 		} else if (strncmp(types, "T7:", 3) == 0) {
2905*fcf3ce44SJohn Forte 			bzero(model->pt_7, sizeof (model->pt_7));
2906*fcf3ce44SJohn Forte 			types += 3;
2907*fcf3ce44SJohn Forte 
2908*fcf3ce44SJohn Forte 			i = 0;
2909*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2910*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2911*fcf3ce44SJohn Forte 				ptr = types;
2912*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2913*fcf3ce44SJohn Forte 					ptr++;
2914*fcf3ce44SJohn Forte 				*ptr = 0;
2915*fcf3ce44SJohn Forte 
2916*fcf3ce44SJohn Forte 				/* Save the value */
2917*fcf3ce44SJohn Forte 				model->pt_7[i++] =
2918*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2919*fcf3ce44SJohn Forte 				model->pt_7[i] = 0;
2920*fcf3ce44SJohn Forte 
2921*fcf3ce44SJohn Forte 				/*
2922*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2923*fcf3ce44SJohn Forte 				 * "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
2924*fcf3ce44SJohn Forte 				 */
2925*fcf3ce44SJohn Forte 
2926*fcf3ce44SJohn Forte 				/* Move the str pointer */
2927*fcf3ce44SJohn Forte 				types = ptr + 1;
2928*fcf3ce44SJohn Forte 			}
2929*fcf3ce44SJohn Forte 		} else if (strncmp(types, "TA:", 3) == 0) {
2930*fcf3ce44SJohn Forte 			bzero(model->pt_A, sizeof (model->pt_A));
2931*fcf3ce44SJohn Forte 			types += 3;
2932*fcf3ce44SJohn Forte 
2933*fcf3ce44SJohn Forte 			i = 0;
2934*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2935*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2936*fcf3ce44SJohn Forte 				ptr = types;
2937*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2938*fcf3ce44SJohn Forte 					ptr++;
2939*fcf3ce44SJohn Forte 				*ptr = 0;
2940*fcf3ce44SJohn Forte 
2941*fcf3ce44SJohn Forte 				/* Save the value */
2942*fcf3ce44SJohn Forte 				model->pt_A[i++] =
2943*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2944*fcf3ce44SJohn Forte 
2945*fcf3ce44SJohn Forte 				/*
2946*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2947*fcf3ce44SJohn Forte 				 * "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
2948*fcf3ce44SJohn Forte 				 */
2949*fcf3ce44SJohn Forte 
2950*fcf3ce44SJohn Forte 				/* Move the str pointer */
2951*fcf3ce44SJohn Forte 				types = ptr + 1;
2952*fcf3ce44SJohn Forte 			}
2953*fcf3ce44SJohn Forte 		} else if (strncmp(types, "TB:", 3) == 0) {
2954*fcf3ce44SJohn Forte 			bzero(model->pt_B, sizeof (model->pt_B));
2955*fcf3ce44SJohn Forte 			types += 3;
2956*fcf3ce44SJohn Forte 
2957*fcf3ce44SJohn Forte 			i = 0;
2958*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2959*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2960*fcf3ce44SJohn Forte 				ptr = types;
2961*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2962*fcf3ce44SJohn Forte 					ptr++;
2963*fcf3ce44SJohn Forte 				*ptr = 0;
2964*fcf3ce44SJohn Forte 
2965*fcf3ce44SJohn Forte 				/* Save the value */
2966*fcf3ce44SJohn Forte 				model->pt_B[i++] =
2967*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2968*fcf3ce44SJohn Forte 
2969*fcf3ce44SJohn Forte 				/*
2970*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2971*fcf3ce44SJohn Forte 				 * "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
2972*fcf3ce44SJohn Forte 				 */
2973*fcf3ce44SJohn Forte 
2974*fcf3ce44SJohn Forte 				/* Move the str pointer */
2975*fcf3ce44SJohn Forte 				types = ptr + 1;
2976*fcf3ce44SJohn Forte 			}
2977*fcf3ce44SJohn Forte 		} else if (strncmp(types, "TFF:", 4) == 0) {
2978*fcf3ce44SJohn Forte 			bzero(model->pt_FF, sizeof (model->pt_FF));
2979*fcf3ce44SJohn Forte 			types += 4;
2980*fcf3ce44SJohn Forte 
2981*fcf3ce44SJohn Forte 			i = 0;
2982*fcf3ce44SJohn Forte 			while (*types && *types != 'T') {
2983*fcf3ce44SJohn Forte 				/* Null terminate the next value */
2984*fcf3ce44SJohn Forte 				ptr = types;
2985*fcf3ce44SJohn Forte 				while (*ptr && (*ptr != ','))
2986*fcf3ce44SJohn Forte 					ptr++;
2987*fcf3ce44SJohn Forte 				*ptr = 0;
2988*fcf3ce44SJohn Forte 
2989*fcf3ce44SJohn Forte 				/* Save the value */
2990*fcf3ce44SJohn Forte 				model->pt_FF[i++] =
2991*fcf3ce44SJohn Forte 				    (uint8_t)emlxs_strtol(types, 16);
2992*fcf3ce44SJohn Forte 
2993*fcf3ce44SJohn Forte 				/*
2994*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
2995*fcf3ce44SJohn Forte 				 * "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
2996*fcf3ce44SJohn Forte 				 */
2997*fcf3ce44SJohn Forte 
2998*fcf3ce44SJohn Forte 				/* Move the str pointer */
2999*fcf3ce44SJohn Forte 				types = ptr + 1;
3000*fcf3ce44SJohn Forte 			}
3001*fcf3ce44SJohn Forte 		} else {
3002*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
3003*fcf3ce44SJohn Forte 			    "Unknown prog type string = %s", types);
3004*fcf3ce44SJohn Forte 			break;
3005*fcf3ce44SJohn Forte 		}
3006*fcf3ce44SJohn Forte 	}
3007*fcf3ce44SJohn Forte 
3008*fcf3ce44SJohn Forte 	return;
3009*fcf3ce44SJohn Forte 
3010*fcf3ce44SJohn Forte } /* emlxs_parse_prog_types() */
3011*fcf3ce44SJohn Forte 
3012*fcf3ce44SJohn Forte 
3013*fcf3ce44SJohn Forte static void
3014*fcf3ce44SJohn Forte emlxs_build_prog_types(emlxs_hba_t *hba, char *prog_types)
3015*fcf3ce44SJohn Forte {
3016*fcf3ce44SJohn Forte 	uint32_t i;
3017*fcf3ce44SJohn Forte 	uint32_t found = 0;
3018*fcf3ce44SJohn Forte 	char buffer[256];
3019*fcf3ce44SJohn Forte 
3020*fcf3ce44SJohn Forte 	bzero(prog_types, 256);
3021*fcf3ce44SJohn Forte 
3022*fcf3ce44SJohn Forte 	/* Rebuild the prog type string */
3023*fcf3ce44SJohn Forte 	if (hba->model_info.pt_2[0]) {
3024*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "T2:");
3025*fcf3ce44SJohn Forte 		found = 1;
3026*fcf3ce44SJohn Forte 
3027*fcf3ce44SJohn Forte 		i = 0;
3028*fcf3ce44SJohn Forte 		while (hba->model_info.pt_2[i] && i < 8) {
3029*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_2[i]);
3030*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3031*fcf3ce44SJohn Forte 			i++;
3032*fcf3ce44SJohn Forte 		}
3033*fcf3ce44SJohn Forte 	}
3034*fcf3ce44SJohn Forte 	if (hba->model_info.pt_3[0]) {
3035*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "T3:");
3036*fcf3ce44SJohn Forte 		found = 1;
3037*fcf3ce44SJohn Forte 
3038*fcf3ce44SJohn Forte 		i = 0;
3039*fcf3ce44SJohn Forte 		while (hba->model_info.pt_3[i] && i < 8) {
3040*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_3[i]);
3041*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3042*fcf3ce44SJohn Forte 			i++;
3043*fcf3ce44SJohn Forte 
3044*fcf3ce44SJohn Forte 		}
3045*fcf3ce44SJohn Forte 	}
3046*fcf3ce44SJohn Forte 	if (hba->model_info.pt_6[0]) {
3047*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "T6:");
3048*fcf3ce44SJohn Forte 		found = 1;
3049*fcf3ce44SJohn Forte 
3050*fcf3ce44SJohn Forte 		i = 0;
3051*fcf3ce44SJohn Forte 		while (hba->model_info.pt_6[i] && i < 8) {
3052*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_6[i]);
3053*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3054*fcf3ce44SJohn Forte 			i++;
3055*fcf3ce44SJohn Forte 		}
3056*fcf3ce44SJohn Forte 	}
3057*fcf3ce44SJohn Forte 	if (hba->model_info.pt_7[0]) {
3058*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "T7:");
3059*fcf3ce44SJohn Forte 		found = 1;
3060*fcf3ce44SJohn Forte 
3061*fcf3ce44SJohn Forte 		i = 0;
3062*fcf3ce44SJohn Forte 		while (hba->model_info.pt_7[i] && i < 8) {
3063*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_7[i]);
3064*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3065*fcf3ce44SJohn Forte 			i++;
3066*fcf3ce44SJohn Forte 		}
3067*fcf3ce44SJohn Forte 	}
3068*fcf3ce44SJohn Forte 	if (hba->model_info.pt_A[0]) {
3069*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "TA:");
3070*fcf3ce44SJohn Forte 		found = 1;
3071*fcf3ce44SJohn Forte 
3072*fcf3ce44SJohn Forte 		i = 0;
3073*fcf3ce44SJohn Forte 		while (hba->model_info.pt_A[i] && i < 8) {
3074*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_A[i]);
3075*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3076*fcf3ce44SJohn Forte 			i++;
3077*fcf3ce44SJohn Forte 		}
3078*fcf3ce44SJohn Forte 	}
3079*fcf3ce44SJohn Forte 	if (hba->model_info.pt_B[0]) {
3080*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "TB:");
3081*fcf3ce44SJohn Forte 		found = 1;
3082*fcf3ce44SJohn Forte 
3083*fcf3ce44SJohn Forte 		i = 0;
3084*fcf3ce44SJohn Forte 		while (hba->model_info.pt_B[i] && i < 8) {
3085*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_B[i]);
3086*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3087*fcf3ce44SJohn Forte 			i++;
3088*fcf3ce44SJohn Forte 		}
3089*fcf3ce44SJohn Forte 	}
3090*fcf3ce44SJohn Forte 	if (hba->model_info.pt_FF[0]) {
3091*fcf3ce44SJohn Forte 		(void) strcat(prog_types, "TFF:");
3092*fcf3ce44SJohn Forte 		found = 1;
3093*fcf3ce44SJohn Forte 
3094*fcf3ce44SJohn Forte 		i = 0;
3095*fcf3ce44SJohn Forte 		while (hba->model_info.pt_FF[i] && i < 8) {
3096*fcf3ce44SJohn Forte 			(void) sprintf(buffer, "%X,", hba->model_info.pt_FF[i]);
3097*fcf3ce44SJohn Forte 			(void) strcat(prog_types, buffer);
3098*fcf3ce44SJohn Forte 			i++;
3099*fcf3ce44SJohn Forte 		}
3100*fcf3ce44SJohn Forte 	}
3101*fcf3ce44SJohn Forte 	if (found) {
3102*fcf3ce44SJohn Forte 		/* Terminate at the last comma in string */
3103*fcf3ce44SJohn Forte 		prog_types[(strlen(prog_types) - 1)] = 0;
3104*fcf3ce44SJohn Forte 	}
3105*fcf3ce44SJohn Forte 	return;
3106*fcf3ce44SJohn Forte 
3107*fcf3ce44SJohn Forte } /* emlxs_build_prog_types() */
3108*fcf3ce44SJohn Forte 
3109*fcf3ce44SJohn Forte 
3110*fcf3ce44SJohn Forte 
3111*fcf3ce44SJohn Forte 
3112*fcf3ce44SJohn Forte extern uint32_t
3113*fcf3ce44SJohn Forte emlxs_init_adapter_info(emlxs_hba_t *hba)
3114*fcf3ce44SJohn Forte {
3115*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3116*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
3117*fcf3ce44SJohn Forte 	uint32_t pci_id;
3118*fcf3ce44SJohn Forte 	uint32_t cache_line;
3119*fcf3ce44SJohn Forte 	uint32_t channels;
3120*fcf3ce44SJohn Forte 	uint16_t device_id;
3121*fcf3ce44SJohn Forte 	uint16_t ssdid;
3122*fcf3ce44SJohn Forte 	uint32_t i;
3123*fcf3ce44SJohn Forte 	uint32_t found = 0;
3124*fcf3ce44SJohn Forte 
3125*fcf3ce44SJohn Forte 	cfg = &CFG;
3126*fcf3ce44SJohn Forte 
3127*fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
3128*fcf3ce44SJohn Forte 		if (hba->pci_acc_handle == NULL) {
3129*fcf3ce44SJohn Forte 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
3130*fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
3131*fcf3ce44SJohn Forte 
3132*fcf3ce44SJohn Forte 			hba->model_info.device_id = 0;
3133*fcf3ce44SJohn Forte 
3134*fcf3ce44SJohn Forte 			return (0);
3135*fcf3ce44SJohn Forte 		}
3136*fcf3ce44SJohn Forte 		/* Read the PCI device id */
3137*fcf3ce44SJohn Forte 		pci_id = ddi_get32(hba->pci_acc_handle,
3138*fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
3139*fcf3ce44SJohn Forte 		device_id = (uint16_t)(pci_id >> 16);
3140*fcf3ce44SJohn Forte 
3141*fcf3ce44SJohn Forte 		/* Find matching adapter model */
3142*fcf3ce44SJohn Forte 		for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
3143*fcf3ce44SJohn Forte 			if (emlxs_sbus_model[i].device_id == device_id) {
3144*fcf3ce44SJohn Forte 				bcopy(&emlxs_sbus_model[i], &hba->model_info,
3145*fcf3ce44SJohn Forte 				    sizeof (emlxs_model_t));
3146*fcf3ce44SJohn Forte 				found = 1;
3147*fcf3ce44SJohn Forte 				break;
3148*fcf3ce44SJohn Forte 			}
3149*fcf3ce44SJohn Forte 		}
3150*fcf3ce44SJohn Forte 
3151*fcf3ce44SJohn Forte 		/* If not found then use the unknown model */
3152*fcf3ce44SJohn Forte 		if (!found) {
3153*fcf3ce44SJohn Forte 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
3154*fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
3155*fcf3ce44SJohn Forte 
3156*fcf3ce44SJohn Forte 			hba->model_info.device_id = device_id;
3157*fcf3ce44SJohn Forte 
3158*fcf3ce44SJohn Forte 			return (0);
3159*fcf3ce44SJohn Forte 		}
3160*fcf3ce44SJohn Forte 	} else {	/* PCI model */
3161*fcf3ce44SJohn Forte 		if (hba->pci_acc_handle == NULL) {
3162*fcf3ce44SJohn Forte 			bcopy(&emlxs_pci_model[0], &hba->model_info,
3163*fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
3164*fcf3ce44SJohn Forte 
3165*fcf3ce44SJohn Forte 			hba->model_info.device_id = 0;
3166*fcf3ce44SJohn Forte 
3167*fcf3ce44SJohn Forte 			return (0);
3168*fcf3ce44SJohn Forte 		}
3169*fcf3ce44SJohn Forte 		/* Read the PCI device id */
3170*fcf3ce44SJohn Forte 		device_id = ddi_get16(hba->pci_acc_handle,
3171*fcf3ce44SJohn Forte 		    (uint16_t *)(hba->pci_addr + PCI_DEVICE_ID_REGISTER));
3172*fcf3ce44SJohn Forte 
3173*fcf3ce44SJohn Forte 		/* Read the PCI Subsystem id */
3174*fcf3ce44SJohn Forte 		ssdid = ddi_get16(hba->pci_acc_handle,
3175*fcf3ce44SJohn Forte 		    (uint16_t *)(hba->pci_addr + PCI_SSDID_REGISTER));
3176*fcf3ce44SJohn Forte 
3177*fcf3ce44SJohn Forte 		if (ssdid == 0 || ssdid == 0xffff) {
3178*fcf3ce44SJohn Forte 			ssdid = device_id;
3179*fcf3ce44SJohn Forte 		}
3180*fcf3ce44SJohn Forte 		/* Read the Cache Line reg */
3181*fcf3ce44SJohn Forte 		cache_line = ddi_get32(hba->pci_acc_handle,
3182*fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + PCI_CACHE_LINE_REGISTER));
3183*fcf3ce44SJohn Forte 
3184*fcf3ce44SJohn Forte 		/* Check for the multifunction bit being set */
3185*fcf3ce44SJohn Forte 		if ((cache_line & 0x00ff0000) == 0x00800000) {
3186*fcf3ce44SJohn Forte 			channels = 2;
3187*fcf3ce44SJohn Forte 		} else {
3188*fcf3ce44SJohn Forte 			channels = 1;
3189*fcf3ce44SJohn Forte 		}
3190*fcf3ce44SJohn Forte 
3191*fcf3ce44SJohn Forte #ifdef MENLO_TEST
3192*fcf3ce44SJohn Forte 		/* Convert Zephyr adapters to Hornet adapters */
3193*fcf3ce44SJohn Forte 		if ((device_id == PCI_DEVICE_ID_LPe11000_M4) &&
3194*fcf3ce44SJohn Forte 		    (cfg[CFG_HORNET_ID].current == 0)) {
3195*fcf3ce44SJohn Forte 			device_id = PCI_DEVICE_ID_LP21000_M;
3196*fcf3ce44SJohn Forte 			ssdid = PCI_SSDID_LP21000_M;
3197*fcf3ce44SJohn Forte 		}
3198*fcf3ce44SJohn Forte #endif	/* MENLO_TEST */
3199*fcf3ce44SJohn Forte 
3200*fcf3ce44SJohn Forte 		/* If device ids are unique, then use them for search */
3201*fcf3ce44SJohn Forte 		if (device_id != ssdid) {
3202*fcf3ce44SJohn Forte 			if (channels > 1) {
3203*fcf3ce44SJohn Forte 				/*
3204*fcf3ce44SJohn Forte 				 * Find matching adapter model using
3205*fcf3ce44SJohn Forte 				 * device_id, ssdid and channels
3206*fcf3ce44SJohn Forte 				 */
3207*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
3208*fcf3ce44SJohn Forte 					if ((emlxs_pci_model[i].device_id ==
3209*fcf3ce44SJohn Forte 					    device_id) &&
3210*fcf3ce44SJohn Forte 					    (emlxs_pci_model[i].ssdid ==
3211*fcf3ce44SJohn Forte 					    ssdid) &&
3212*fcf3ce44SJohn Forte 					    (emlxs_pci_model[i].channels ==
3213*fcf3ce44SJohn Forte 					    channels)) {
3214*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
3215*fcf3ce44SJohn Forte 						    &hba->model_info,
3216*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
3217*fcf3ce44SJohn Forte 						found = 1;
3218*fcf3ce44SJohn Forte 						break;
3219*fcf3ce44SJohn Forte 					}
3220*fcf3ce44SJohn Forte 				}
3221*fcf3ce44SJohn Forte 			} else {
3222*fcf3ce44SJohn Forte 				/*
3223*fcf3ce44SJohn Forte 				 * Find matching adapter model using
3224*fcf3ce44SJohn Forte 				 * device_id and ssdid
3225*fcf3ce44SJohn Forte 				 */
3226*fcf3ce44SJohn Forte 				for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
3227*fcf3ce44SJohn Forte 					if ((emlxs_pci_model[i].device_id ==
3228*fcf3ce44SJohn Forte 					    device_id) &&
3229*fcf3ce44SJohn Forte 					    (emlxs_pci_model[i].ssdid ==
3230*fcf3ce44SJohn Forte 					    ssdid)) {
3231*fcf3ce44SJohn Forte 						bcopy(&emlxs_pci_model[i],
3232*fcf3ce44SJohn Forte 						    &hba->model_info,
3233*fcf3ce44SJohn Forte 						    sizeof (emlxs_model_t));
3234*fcf3ce44SJohn Forte 						found = 1;
3235*fcf3ce44SJohn Forte 						break;
3236*fcf3ce44SJohn Forte 					}
3237*fcf3ce44SJohn Forte 				}
3238*fcf3ce44SJohn Forte 			}
3239*fcf3ce44SJohn Forte 		}
3240*fcf3ce44SJohn Forte 		/* If adapter not found, try again */
3241*fcf3ce44SJohn Forte 		if (!found) {
3242*fcf3ce44SJohn Forte 			/* Find matching adapter model */
3243*fcf3ce44SJohn Forte 			for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
3244*fcf3ce44SJohn Forte 				if (emlxs_pci_model[i].device_id == device_id &&
3245*fcf3ce44SJohn Forte 				    emlxs_pci_model[i].channels == channels) {
3246*fcf3ce44SJohn Forte 					bcopy(&emlxs_pci_model[i],
3247*fcf3ce44SJohn Forte 					    &hba->model_info,
3248*fcf3ce44SJohn Forte 					    sizeof (emlxs_model_t));
3249*fcf3ce44SJohn Forte 					found = 1;
3250*fcf3ce44SJohn Forte 					break;
3251*fcf3ce44SJohn Forte 				}
3252*fcf3ce44SJohn Forte 			}
3253*fcf3ce44SJohn Forte 		}
3254*fcf3ce44SJohn Forte 		/* If adapter not found, try one last time */
3255*fcf3ce44SJohn Forte 		if (!found) {
3256*fcf3ce44SJohn Forte 			/* Find matching adapter model */
3257*fcf3ce44SJohn Forte 			for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
3258*fcf3ce44SJohn Forte 				if (emlxs_pci_model[i].device_id == device_id) {
3259*fcf3ce44SJohn Forte 					bcopy(&emlxs_pci_model[i],
3260*fcf3ce44SJohn Forte 					    &hba->model_info,
3261*fcf3ce44SJohn Forte 					    sizeof (emlxs_model_t));
3262*fcf3ce44SJohn Forte 					found = 1;
3263*fcf3ce44SJohn Forte 					break;
3264*fcf3ce44SJohn Forte 				}
3265*fcf3ce44SJohn Forte 			}
3266*fcf3ce44SJohn Forte 		}
3267*fcf3ce44SJohn Forte 		/* If not found, set adapter to unknown */
3268*fcf3ce44SJohn Forte 		if (!found) {
3269*fcf3ce44SJohn Forte 			bcopy(&emlxs_pci_model[0], &hba->model_info,
3270*fcf3ce44SJohn Forte 			    sizeof (emlxs_model_t));
3271*fcf3ce44SJohn Forte 
3272*fcf3ce44SJohn Forte 			hba->model_info.device_id = device_id;
3273*fcf3ce44SJohn Forte 			hba->model_info.ssdid = ssdid;
3274*fcf3ce44SJohn Forte 
3275*fcf3ce44SJohn Forte 			return (0);
3276*fcf3ce44SJohn Forte 		}
3277*fcf3ce44SJohn Forte #ifdef MENLO_TEST
3278*fcf3ce44SJohn Forte 		/* Convert Hornet program types to Zephyr program types */
3279*fcf3ce44SJohn Forte 		if ((hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) &&
3280*fcf3ce44SJohn Forte 		    (cfg[CFG_HORNET_PTYPES].current == 0)) {
3281*fcf3ce44SJohn Forte 			/*
3282*fcf3ce44SJohn Forte 			 * Find matching Zephyr card and copy Zephyr program
3283*fcf3ce44SJohn Forte 			 * types
3284*fcf3ce44SJohn Forte 			 */
3285*fcf3ce44SJohn Forte 			for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
3286*fcf3ce44SJohn Forte 				if ((emlxs_pci_model[i].device_id ==
3287*fcf3ce44SJohn Forte 				    PCI_DEVICE_ID_LPe11000_M4) &&
3288*fcf3ce44SJohn Forte 				    (emlxs_pci_model[i].ssdid ==
3289*fcf3ce44SJohn Forte 				    PCI_SSDID_LPe11000_M4) &&
3290*fcf3ce44SJohn Forte 				    (emlxs_pci_model[i].channels == channels)) {
3291*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_2,
3292*fcf3ce44SJohn Forte 					    hba->model_info.pt_2, 8);
3293*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_3,
3294*fcf3ce44SJohn Forte 					    hba->model_info.pt_3, 8);
3295*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_6,
3296*fcf3ce44SJohn Forte 					    hba->model_info.pt_6, 8);
3297*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_7,
3298*fcf3ce44SJohn Forte 					    hba->model_info.pt_7, 8);
3299*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_A,
3300*fcf3ce44SJohn Forte 					    hba->model_info.pt_A, 8);
3301*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_B,
3302*fcf3ce44SJohn Forte 					    hba->model_info.pt_B, 8);
3303*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_E,
3304*fcf3ce44SJohn Forte 					    hba->model_info.pt_E, 8);
3305*fcf3ce44SJohn Forte 					bcopy(emlxs_pci_model[i].pt_FF,
3306*fcf3ce44SJohn Forte 					    hba->model_info.pt_FF, 8);
3307*fcf3ce44SJohn Forte 					break;
3308*fcf3ce44SJohn Forte 				}
3309*fcf3ce44SJohn Forte 			}
3310*fcf3ce44SJohn Forte 		}
3311*fcf3ce44SJohn Forte #endif	/* MENLO_TEST */
3312*fcf3ce44SJohn Forte 
3313*fcf3ce44SJohn Forte #ifndef SATURN_MSI_SUPPORT
3314*fcf3ce44SJohn Forte 		/*
3315*fcf3ce44SJohn Forte 		 * This will disable MSI support for Saturn adapter's due to
3316*fcf3ce44SJohn Forte 		 * a PCI bus issue
3317*fcf3ce44SJohn Forte 		 */
3318*fcf3ce44SJohn Forte 		if (hba->model_info.chip == EMLXS_SATURN_CHIP) {
3319*fcf3ce44SJohn Forte 			hba->model_info.flags &=
3320*fcf3ce44SJohn Forte 			    ~(EMLXS_MSI_SUPPORTED | EMLXS_MSIX_SUPPORTED);
3321*fcf3ce44SJohn Forte 		}
3322*fcf3ce44SJohn Forte #endif	/* !SATURN_MSI_SUPPORT */
3323*fcf3ce44SJohn Forte 
3324*fcf3ce44SJohn Forte 
3325*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
3326*fcf3ce44SJohn Forte 		/* Verify MSI support */
3327*fcf3ce44SJohn Forte 		if (hba->model_info.flags & EMLXS_MSI_SUPPORTED) {
3328*fcf3ce44SJohn Forte 			uint32_t offset;
3329*fcf3ce44SJohn Forte 			uint32_t reg;
3330*fcf3ce44SJohn Forte 
3331*fcf3ce44SJohn Forte 			/* Scan for MSI capabilities register */
3332*fcf3ce44SJohn Forte 			offset = ddi_get32(hba->pci_acc_handle,
3333*fcf3ce44SJohn Forte 			    (uint32_t *)(hba->pci_addr + PCI_CAP_POINTER));
3334*fcf3ce44SJohn Forte 			offset &= 0xff;
3335*fcf3ce44SJohn Forte 
3336*fcf3ce44SJohn Forte 			while (offset) {
3337*fcf3ce44SJohn Forte 				reg = ddi_get32(hba->pci_acc_handle,
3338*fcf3ce44SJohn Forte 				    (uint32_t *)(hba->pci_addr + offset));
3339*fcf3ce44SJohn Forte 
3340*fcf3ce44SJohn Forte 				if ((reg & 0xff) == MSI_CAP_ID) {
3341*fcf3ce44SJohn Forte 					break;
3342*fcf3ce44SJohn Forte 				}
3343*fcf3ce44SJohn Forte 				offset = (reg >> 8) & 0xff;
3344*fcf3ce44SJohn Forte 			}
3345*fcf3ce44SJohn Forte 
3346*fcf3ce44SJohn Forte 			if (offset) {
3347*fcf3ce44SJohn Forte 				hba->msi_cap_offset = offset + 2;
3348*fcf3ce44SJohn Forte 			} else {
3349*fcf3ce44SJohn Forte 				hba->msi_cap_offset = 0;
3350*fcf3ce44SJohn Forte 				hba->model_info.flags &= ~EMLXS_MSI_SUPPORTED;
3351*fcf3ce44SJohn Forte 
3352*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3353*fcf3ce44SJohn Forte 				    "MSI: control_reg capability not found!");
3354*fcf3ce44SJohn Forte 			}
3355*fcf3ce44SJohn Forte 		}
3356*fcf3ce44SJohn Forte 		/* Verify MSI-X support */
3357*fcf3ce44SJohn Forte 		if (hba->model_info.flags & EMLXS_MSIX_SUPPORTED) {
3358*fcf3ce44SJohn Forte 			uint32_t offset;
3359*fcf3ce44SJohn Forte 			uint32_t reg;
3360*fcf3ce44SJohn Forte 
3361*fcf3ce44SJohn Forte 			/* Scan for MSI capabilities register */
3362*fcf3ce44SJohn Forte 			offset = ddi_get32(hba->pci_acc_handle,
3363*fcf3ce44SJohn Forte 			    (uint32_t *)(hba->pci_addr + PCI_CAP_POINTER));
3364*fcf3ce44SJohn Forte 			offset &= 0xff;
3365*fcf3ce44SJohn Forte 
3366*fcf3ce44SJohn Forte 			while (offset) {
3367*fcf3ce44SJohn Forte 				reg = ddi_get32(hba->pci_acc_handle,
3368*fcf3ce44SJohn Forte 				    (uint32_t *)(hba->pci_addr + offset));
3369*fcf3ce44SJohn Forte 
3370*fcf3ce44SJohn Forte 				if ((reg & 0xff) == MSIX_CAP_ID) {
3371*fcf3ce44SJohn Forte 					break;
3372*fcf3ce44SJohn Forte 				}
3373*fcf3ce44SJohn Forte 				offset = (reg >> 8) & 0xff;
3374*fcf3ce44SJohn Forte 			}
3375*fcf3ce44SJohn Forte 
3376*fcf3ce44SJohn Forte 			if (offset) {
3377*fcf3ce44SJohn Forte 				hba->msix_cap_offset = offset;
3378*fcf3ce44SJohn Forte 			} else {
3379*fcf3ce44SJohn Forte 				hba->msix_cap_offset = 0;
3380*fcf3ce44SJohn Forte 				hba->model_info.flags &= ~EMLXS_MSIX_SUPPORTED;
3381*fcf3ce44SJohn Forte 
3382*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3383*fcf3ce44SJohn Forte 				    "MSIX: control_reg capability not found!");
3384*fcf3ce44SJohn Forte 			}
3385*fcf3ce44SJohn Forte 		}
3386*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
3387*fcf3ce44SJohn Forte 
3388*fcf3ce44SJohn Forte 	}
3389*fcf3ce44SJohn Forte 
3390*fcf3ce44SJohn Forte 	return (1);
3391*fcf3ce44SJohn Forte 
3392*fcf3ce44SJohn Forte } /* emlxs_init_adapter_info()  */
3393*fcf3ce44SJohn Forte 
3394*fcf3ce44SJohn Forte 
3395*fcf3ce44SJohn Forte /* EMLXS_PORT_LOCK must be held when call this routine */
3396*fcf3ce44SJohn Forte static uint32_t
3397*fcf3ce44SJohn Forte emlxs_get_attention(emlxs_hba_t *hba, uint32_t msgid)
3398*fcf3ce44SJohn Forte {
3399*fcf3ce44SJohn Forte 	uint32_t ha_copy = 0;
3400*fcf3ce44SJohn Forte 	uint32_t ha_copy2;
3401*fcf3ce44SJohn Forte 	uint32_t mask = hba->hc_copy;
3402*fcf3ce44SJohn Forte 
3403*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
3404*fcf3ce44SJohn Forte 
3405*fcf3ce44SJohn Forte read_ha_register:
3406*fcf3ce44SJohn Forte 
3407*fcf3ce44SJohn Forte 	/* Check for default MSI interrupt */
3408*fcf3ce44SJohn Forte 	if (msgid == 0) {
3409*fcf3ce44SJohn Forte 		/* Read host attention register to determine interrupt source */
3410*fcf3ce44SJohn Forte 		ha_copy2 = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
3411*fcf3ce44SJohn Forte 
3412*fcf3ce44SJohn Forte 		/* Filter out MSI non-default attention bits */
3413*fcf3ce44SJohn Forte 		ha_copy2 &= ~(hba->intr_cond);
3414*fcf3ce44SJohn Forte 	}
3415*fcf3ce44SJohn Forte 	/* Check for polled or fixed type interrupt */
3416*fcf3ce44SJohn Forte 	else if (msgid == -1) {
3417*fcf3ce44SJohn Forte 		/* Read host attention register to determine interrupt source */
3418*fcf3ce44SJohn Forte 		ha_copy2 = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
3419*fcf3ce44SJohn Forte 	}
3420*fcf3ce44SJohn Forte 	/* Otherwise, assume a mapped MSI interrupt */
3421*fcf3ce44SJohn Forte 	else {
3422*fcf3ce44SJohn Forte 		/* Convert MSI msgid to mapped attention bits */
3423*fcf3ce44SJohn Forte 		ha_copy2 = hba->intr_map[msgid];
3424*fcf3ce44SJohn Forte 	}
3425*fcf3ce44SJohn Forte 
3426*fcf3ce44SJohn Forte #else	/* !MSI_SUPPORT */
3427*fcf3ce44SJohn Forte 
3428*fcf3ce44SJohn Forte 	/* Read host attention register to determine interrupt source */
3429*fcf3ce44SJohn Forte 	ha_copy2 = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
3430*fcf3ce44SJohn Forte 
3431*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
3432*fcf3ce44SJohn Forte 
3433*fcf3ce44SJohn Forte 	/* Check if Hardware error interrupt is enabled */
3434*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_ERATT) && !(mask & HC_ERINT_ENA)) {
3435*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_ERATT;
3436*fcf3ce44SJohn Forte 	}
3437*fcf3ce44SJohn Forte 	/* Check if link interrupt is enabled */
3438*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_LATT) && !(mask & HC_LAINT_ENA)) {
3439*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_LATT;
3440*fcf3ce44SJohn Forte 	}
3441*fcf3ce44SJohn Forte 	/* Check if Mailbox interrupt is enabled */
3442*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_MBATT) && !(mask & HC_MBINT_ENA)) {
3443*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_MBATT;
3444*fcf3ce44SJohn Forte 	}
3445*fcf3ce44SJohn Forte 	/* Check if ring0 interrupt is enabled */
3446*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_R0ATT) && !(mask & HC_R0INT_ENA)) {
3447*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_R0ATT;
3448*fcf3ce44SJohn Forte 	}
3449*fcf3ce44SJohn Forte 	/* Check if ring1 interrupt is enabled */
3450*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_R1ATT) && !(mask & HC_R1INT_ENA)) {
3451*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_R1ATT;
3452*fcf3ce44SJohn Forte 	}
3453*fcf3ce44SJohn Forte 	/* Check if ring2 interrupt is enabled */
3454*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_R2ATT) && !(mask & HC_R2INT_ENA)) {
3455*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_R2ATT;
3456*fcf3ce44SJohn Forte 	}
3457*fcf3ce44SJohn Forte 	/* Check if ring3 interrupt is enabled */
3458*fcf3ce44SJohn Forte 	if ((ha_copy2 & HA_R3ATT) && !(mask & HC_R3INT_ENA)) {
3459*fcf3ce44SJohn Forte 		ha_copy2 &= ~HA_R3ATT;
3460*fcf3ce44SJohn Forte 	}
3461*fcf3ce44SJohn Forte 	/* Accumulate attention bits */
3462*fcf3ce44SJohn Forte 	ha_copy |= ha_copy2;
3463*fcf3ce44SJohn Forte 
3464*fcf3ce44SJohn Forte 	/* Clear attentions except for error, link, and autoclear(MSIX) */
3465*fcf3ce44SJohn Forte 	ha_copy2 &= ~(HA_ERATT | HA_LATT /* | hba->intr_autoClear */);
3466*fcf3ce44SJohn Forte 
3467*fcf3ce44SJohn Forte 	if (ha_copy2) {
3468*fcf3ce44SJohn Forte 		WRITE_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr), ha_copy2);
3469*fcf3ce44SJohn Forte 	}
3470*fcf3ce44SJohn Forte 	return (ha_copy);
3471*fcf3ce44SJohn Forte 
3472*fcf3ce44SJohn Forte } /* emlxs_get_attention() */
3473*fcf3ce44SJohn Forte 
3474*fcf3ce44SJohn Forte 
3475*fcf3ce44SJohn Forte static void
3476*fcf3ce44SJohn Forte emlxs_proc_attention(emlxs_hba_t *hba, uint32_t ha_copy)
3477*fcf3ce44SJohn Forte {
3478*fcf3ce44SJohn Forte 	/* ha_copy should be pre-filtered */
3479*fcf3ce44SJohn Forte 
3480*fcf3ce44SJohn Forte 	/*
3481*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
3482*fcf3ce44SJohn Forte 	 * "emlxs_proc_attention: ha_copy=%x", ha_copy);
3483*fcf3ce44SJohn Forte 	 */
3484*fcf3ce44SJohn Forte 
3485*fcf3ce44SJohn Forte 	if (hba->state < FC_WARM_START) {
3486*fcf3ce44SJohn Forte 		return;
3487*fcf3ce44SJohn Forte 	}
3488*fcf3ce44SJohn Forte 	if (!ha_copy) {
3489*fcf3ce44SJohn Forte 		return;
3490*fcf3ce44SJohn Forte 	}
3491*fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
3492*fcf3ce44SJohn Forte 		(void) READ_SBUS_CSR_REG(hba, FC_SHS_REG(hba,
3493*fcf3ce44SJohn Forte 		    hba->sbus_csr_addr));
3494*fcf3ce44SJohn Forte 	}
3495*fcf3ce44SJohn Forte 	/* Adapter error */
3496*fcf3ce44SJohn Forte 	if (ha_copy & HA_ERATT) {
3497*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[6]++;
3498*fcf3ce44SJohn Forte 		emlxs_handle_ff_error(hba);
3499*fcf3ce44SJohn Forte 		return;
3500*fcf3ce44SJohn Forte 	}
3501*fcf3ce44SJohn Forte 	/* Mailbox interrupt */
3502*fcf3ce44SJohn Forte 	if (ha_copy & HA_MBATT) {
3503*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[5]++;
3504*fcf3ce44SJohn Forte 		(void) emlxs_handle_mb_event(hba);
3505*fcf3ce44SJohn Forte 	}
3506*fcf3ce44SJohn Forte 	/* Link Attention interrupt */
3507*fcf3ce44SJohn Forte 	if (ha_copy & HA_LATT) {
3508*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[4]++;
3509*fcf3ce44SJohn Forte 		emlxs_handle_link_event(hba);
3510*fcf3ce44SJohn Forte 	}
3511*fcf3ce44SJohn Forte 	/* event on ring 0 - FCP Ring */
3512*fcf3ce44SJohn Forte 	if (ha_copy & HA_R0ATT) {
3513*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[0]++;
3514*fcf3ce44SJohn Forte 		emlxs_handle_ring_event(hba, 0, ha_copy);
3515*fcf3ce44SJohn Forte 	}
3516*fcf3ce44SJohn Forte 	/* event on ring 1 - IP Ring */
3517*fcf3ce44SJohn Forte 	if (ha_copy & HA_R1ATT) {
3518*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[1]++;
3519*fcf3ce44SJohn Forte 		emlxs_handle_ring_event(hba, 1, ha_copy);
3520*fcf3ce44SJohn Forte 	}
3521*fcf3ce44SJohn Forte 	/* event on ring 2 - ELS Ring */
3522*fcf3ce44SJohn Forte 	if (ha_copy & HA_R2ATT) {
3523*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[2]++;
3524*fcf3ce44SJohn Forte 		emlxs_handle_ring_event(hba, 2, ha_copy);
3525*fcf3ce44SJohn Forte 	}
3526*fcf3ce44SJohn Forte 	/* event on ring 3 - CT Ring */
3527*fcf3ce44SJohn Forte 	if (ha_copy & HA_R3ATT) {
3528*fcf3ce44SJohn Forte 		HBASTATS.IntrEvent[3]++;
3529*fcf3ce44SJohn Forte 		emlxs_handle_ring_event(hba, 3, ha_copy);
3530*fcf3ce44SJohn Forte 	}
3531*fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
3532*fcf3ce44SJohn Forte 		WRITE_SBUS_CSR_REG(hba,
3533*fcf3ce44SJohn Forte 		    FC_SHS_REG(hba, hba->sbus_csr_addr),
3534*fcf3ce44SJohn Forte 		    SBUS_STAT_IP);
3535*fcf3ce44SJohn Forte 	}
3536*fcf3ce44SJohn Forte 	/* Set heartbeat flag to show activity */
3537*fcf3ce44SJohn Forte 	hba->heartbeat_flag = 1;
3538*fcf3ce44SJohn Forte 
3539*fcf3ce44SJohn Forte 	return;
3540*fcf3ce44SJohn Forte 
3541*fcf3ce44SJohn Forte } /* emlxs_proc_attention() */
3542*fcf3ce44SJohn Forte 
3543*fcf3ce44SJohn Forte 
3544*fcf3ce44SJohn Forte #ifdef MSI_SUPPORT
3545*fcf3ce44SJohn Forte 
3546*fcf3ce44SJohn Forte static uint32_t
3547*fcf3ce44SJohn Forte emlxs_msi_intr(char *arg1, char *arg2)
3548*fcf3ce44SJohn Forte {
3549*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
3550*fcf3ce44SJohn Forte 	uint16_t msgid;
3551*fcf3ce44SJohn Forte 	uint32_t hc_copy;
3552*fcf3ce44SJohn Forte 	uint32_t ha_copy;
3553*fcf3ce44SJohn Forte 	uint32_t restore = 0;
3554*fcf3ce44SJohn Forte 
3555*fcf3ce44SJohn Forte 	/*
3556*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "emlxs_msi_intr:
3557*fcf3ce44SJohn Forte 	 * arg1=%p arg2=%p", arg1, arg2);
3558*fcf3ce44SJohn Forte 	 */
3559*fcf3ce44SJohn Forte 
3560*fcf3ce44SJohn Forte 	/* Check for legacy interrupt handling */
3561*fcf3ce44SJohn Forte 	if (hba->intr_type == DDI_INTR_TYPE_FIXED) {
3562*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
3563*fcf3ce44SJohn Forte 
3564*fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
3565*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
3566*fcf3ce44SJohn Forte 
3567*fcf3ce44SJohn Forte 			if (hba->bus_type == SBUS_FC) {
3568*fcf3ce44SJohn Forte 				return (DDI_INTR_CLAIMED);
3569*fcf3ce44SJohn Forte 			} else {
3570*fcf3ce44SJohn Forte 				return (DDI_INTR_UNCLAIMED);
3571*fcf3ce44SJohn Forte 			}
3572*fcf3ce44SJohn Forte 		}
3573*fcf3ce44SJohn Forte 		/* Get host attention bits */
3574*fcf3ce44SJohn Forte 		ha_copy = emlxs_get_attention(hba, -1);
3575*fcf3ce44SJohn Forte 
3576*fcf3ce44SJohn Forte 		if (ha_copy == 0) {
3577*fcf3ce44SJohn Forte 			if (hba->intr_unclaimed) {
3578*fcf3ce44SJohn Forte 				mutex_exit(&EMLXS_PORT_LOCK);
3579*fcf3ce44SJohn Forte 				return (DDI_INTR_UNCLAIMED);
3580*fcf3ce44SJohn Forte 			}
3581*fcf3ce44SJohn Forte 			hba->intr_unclaimed = 1;
3582*fcf3ce44SJohn Forte 		} else {
3583*fcf3ce44SJohn Forte 			hba->intr_unclaimed = 0;
3584*fcf3ce44SJohn Forte 		}
3585*fcf3ce44SJohn Forte 
3586*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
3587*fcf3ce44SJohn Forte 
3588*fcf3ce44SJohn Forte 		/* Process the interrupt */
3589*fcf3ce44SJohn Forte 		emlxs_proc_attention(hba, ha_copy);
3590*fcf3ce44SJohn Forte 
3591*fcf3ce44SJohn Forte 		return (DDI_INTR_CLAIMED);
3592*fcf3ce44SJohn Forte 	}
3593*fcf3ce44SJohn Forte 	/* DDI_INTR_TYPE_MSI  */
3594*fcf3ce44SJohn Forte 	/* DDI_INTR_TYPE_MSIX */
3595*fcf3ce44SJohn Forte 
3596*fcf3ce44SJohn Forte 	/* Get MSI message id */
3597*fcf3ce44SJohn Forte 	msgid = (uint16_t)(unsigned long)arg2;
3598*fcf3ce44SJohn Forte 
3599*fcf3ce44SJohn Forte 	/* Validate the message id */
3600*fcf3ce44SJohn Forte 	if (msgid >= hba->intr_count) {
3601*fcf3ce44SJohn Forte 		msgid = 0;
3602*fcf3ce44SJohn Forte 	}
3603*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_INTR_LOCK(msgid));
3604*fcf3ce44SJohn Forte 
3605*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
3606*fcf3ce44SJohn Forte 
3607*fcf3ce44SJohn Forte 	/* Check if adapter is offline */
3608*fcf3ce44SJohn Forte 	if (hba->flag & FC_OFFLINE_MODE) {
3609*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
3610*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_INTR_LOCK(msgid));
3611*fcf3ce44SJohn Forte 
3612*fcf3ce44SJohn Forte 		/* Always claim an MSI interrupt */
3613*fcf3ce44SJohn Forte 		return (DDI_INTR_CLAIMED);
3614*fcf3ce44SJohn Forte 	}
3615*fcf3ce44SJohn Forte 	/* Disable interrupts associated with this msgid */
3616*fcf3ce44SJohn Forte 	if (msgid == 0 && (hba->model_info.chip == EMLXS_ZEPHYR_CHIP)) {
3617*fcf3ce44SJohn Forte 		hc_copy = hba->hc_copy & ~hba->intr_mask;
3618*fcf3ce44SJohn Forte 		WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hc_copy);
3619*fcf3ce44SJohn Forte 		restore = 1;
3620*fcf3ce44SJohn Forte 	}
3621*fcf3ce44SJohn Forte 	/* Get host attention bits */
3622*fcf3ce44SJohn Forte 	ha_copy = emlxs_get_attention(hba, msgid);
3623*fcf3ce44SJohn Forte 
3624*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
3625*fcf3ce44SJohn Forte 
3626*fcf3ce44SJohn Forte 	/* Process the interrupt */
3627*fcf3ce44SJohn Forte 	emlxs_proc_attention(hba, ha_copy);
3628*fcf3ce44SJohn Forte 
3629*fcf3ce44SJohn Forte 	/* Restore interrupts */
3630*fcf3ce44SJohn Forte 	if (restore) {
3631*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
3632*fcf3ce44SJohn Forte 		WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
3633*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
3634*fcf3ce44SJohn Forte 	}
3635*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_INTR_LOCK(msgid));
3636*fcf3ce44SJohn Forte 
3637*fcf3ce44SJohn Forte 	return (DDI_INTR_CLAIMED);
3638*fcf3ce44SJohn Forte 
3639*fcf3ce44SJohn Forte } /* emlxs_msi_intr() */
3640*fcf3ce44SJohn Forte 
3641*fcf3ce44SJohn Forte #endif	/* MSI_SUPPORT */
3642*fcf3ce44SJohn Forte 
3643*fcf3ce44SJohn Forte static int
3644*fcf3ce44SJohn Forte emlxs_intx_intr(char *arg)
3645*fcf3ce44SJohn Forte {
3646*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg;
3647*fcf3ce44SJohn Forte 	uint32_t ha_copy = 0;
3648*fcf3ce44SJohn Forte 
3649*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
3650*fcf3ce44SJohn Forte 
3651*fcf3ce44SJohn Forte 	if (hba->flag & FC_OFFLINE_MODE) {
3652*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
3653*fcf3ce44SJohn Forte 
3654*fcf3ce44SJohn Forte 		if (hba->bus_type == SBUS_FC) {
3655*fcf3ce44SJohn Forte 			return (DDI_INTR_CLAIMED);
3656*fcf3ce44SJohn Forte 		} else {
3657*fcf3ce44SJohn Forte 			return (DDI_INTR_UNCLAIMED);
3658*fcf3ce44SJohn Forte 		}
3659*fcf3ce44SJohn Forte 	}
3660*fcf3ce44SJohn Forte 	/* Get host attention bits */
3661*fcf3ce44SJohn Forte 	ha_copy = emlxs_get_attention(hba, -1);
3662*fcf3ce44SJohn Forte 
3663*fcf3ce44SJohn Forte 	if (ha_copy == 0) {
3664*fcf3ce44SJohn Forte 		if (hba->intr_unclaimed) {
3665*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
3666*fcf3ce44SJohn Forte 			return (DDI_INTR_UNCLAIMED);
3667*fcf3ce44SJohn Forte 		}
3668*fcf3ce44SJohn Forte 		hba->intr_unclaimed = 1;
3669*fcf3ce44SJohn Forte 	} else {
3670*fcf3ce44SJohn Forte 		hba->intr_unclaimed = 0;
3671*fcf3ce44SJohn Forte 	}
3672*fcf3ce44SJohn Forte 
3673*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
3674*fcf3ce44SJohn Forte 
3675*fcf3ce44SJohn Forte 	/* Process the interrupt */
3676*fcf3ce44SJohn Forte 	emlxs_proc_attention(hba, ha_copy);
3677*fcf3ce44SJohn Forte 
3678*fcf3ce44SJohn Forte 	return (DDI_INTR_CLAIMED);
3679*fcf3ce44SJohn Forte 
3680*fcf3ce44SJohn Forte } /* emlxs_intx_intr() */
3681*fcf3ce44SJohn Forte 
3682*fcf3ce44SJohn Forte 
3683*fcf3ce44SJohn Forte /* ARGSUSED */
3684*fcf3ce44SJohn Forte static void
3685*fcf3ce44SJohn Forte emlxs_handle_async_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
3686*fcf3ce44SJohn Forte {
3687*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3688*fcf3ce44SJohn Forte 	IOCB *iocb;
3689*fcf3ce44SJohn Forte 
3690*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
3691*fcf3ce44SJohn Forte 
3692*fcf3ce44SJohn Forte 	if (iocb->ulpStatus != 0) {
3693*fcf3ce44SJohn Forte 		return;
3694*fcf3ce44SJohn Forte 	}
3695*fcf3ce44SJohn Forte 	switch (iocb->un.astat.EventCode) {
3696*fcf3ce44SJohn Forte 	case 0x0100:	/* Temp Warning */
3697*fcf3ce44SJohn Forte 
3698*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_warning_msg,
3699*fcf3ce44SJohn Forte 		    "Adapter is very hot (%d �C). Take corrective action.",
3700*fcf3ce44SJohn Forte 		    iocb->ulpContext);
3701*fcf3ce44SJohn Forte 
3702*fcf3ce44SJohn Forte 		emlxs_log_temp_event(port, 0x02, iocb->ulpContext);
3703*fcf3ce44SJohn Forte 
3704*fcf3ce44SJohn Forte 		break;
3705*fcf3ce44SJohn Forte 
3706*fcf3ce44SJohn Forte 
3707*fcf3ce44SJohn Forte 	case 0x0101:	/* Temp Safe */
3708*fcf3ce44SJohn Forte 
3709*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_msg,
3710*fcf3ce44SJohn Forte 		    "Adapter temperature now safe (%d �C).",
3711*fcf3ce44SJohn Forte 		    iocb->ulpContext);
3712*fcf3ce44SJohn Forte 
3713*fcf3ce44SJohn Forte 		emlxs_log_temp_event(port, 0x03, iocb->ulpContext);
3714*fcf3ce44SJohn Forte 
3715*fcf3ce44SJohn Forte 		break;
3716*fcf3ce44SJohn Forte 	}
3717*fcf3ce44SJohn Forte 
3718*fcf3ce44SJohn Forte 	return;
3719*fcf3ce44SJohn Forte 
3720*fcf3ce44SJohn Forte } /* emlxs_handle_async_event() */
3721*fcf3ce44SJohn Forte 
3722*fcf3ce44SJohn Forte 
3723*fcf3ce44SJohn Forte /*
3724*fcf3ce44SJohn Forte  *  emlxs_handle_ff_error
3725*fcf3ce44SJohn Forte  *
3726*fcf3ce44SJohn Forte  *    Description: Processes a FireFly error
3727*fcf3ce44SJohn Forte  *    Runs at Interrupt level
3728*fcf3ce44SJohn Forte  *
3729*fcf3ce44SJohn Forte  */
3730*fcf3ce44SJohn Forte extern void
3731*fcf3ce44SJohn Forte emlxs_handle_ff_error(emlxs_hba_t *hba)
3732*fcf3ce44SJohn Forte {
3733*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3734*fcf3ce44SJohn Forte 	uint32_t status;
3735*fcf3ce44SJohn Forte 	uint32_t status1;
3736*fcf3ce44SJohn Forte 	uint32_t status2;
3737*fcf3ce44SJohn Forte 
3738*fcf3ce44SJohn Forte 	/* do what needs to be done, get error from STATUS REGISTER */
3739*fcf3ce44SJohn Forte 	status = READ_CSR_REG(hba, FC_HS_REG(hba, hba->csr_addr));
3740*fcf3ce44SJohn Forte 
3741*fcf3ce44SJohn Forte 	/* Clear Chip error bit */
3742*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr), HA_ERATT);
3743*fcf3ce44SJohn Forte 
3744*fcf3ce44SJohn Forte 	if (status & HS_OVERTEMP) {
3745*fcf3ce44SJohn Forte 		status1 = READ_SLIM_ADDR(hba,
3746*fcf3ce44SJohn Forte 		    ((volatile uint8_t *) hba->slim_addr + 0xb0));
3747*fcf3ce44SJohn Forte 
3748*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_hardware_error_msg,
3749*fcf3ce44SJohn Forte 		    "Maximum adapter temperature exceeded (%d �C).",
3750*fcf3ce44SJohn Forte 		    status1);
3751*fcf3ce44SJohn Forte 
3752*fcf3ce44SJohn Forte 		hba->flag |= FC_OVERTEMP_EVENT;
3753*fcf3ce44SJohn Forte 		emlxs_log_temp_event(port, 0x01, status1);
3754*fcf3ce44SJohn Forte 	} else {
3755*fcf3ce44SJohn Forte 		status1 = READ_SLIM_ADDR(hba,
3756*fcf3ce44SJohn Forte 		    ((volatile uint8_t *) hba->slim_addr + 0xa8));
3757*fcf3ce44SJohn Forte 		status2 = READ_SLIM_ADDR(hba,
3758*fcf3ce44SJohn Forte 		    ((volatile uint8_t *) hba->slim_addr + 0xac));
3759*fcf3ce44SJohn Forte 
3760*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_hardware_error_msg,
3761*fcf3ce44SJohn Forte 		    "Host Error Attention: status=0x%x status1=0x%x "
3762*fcf3ce44SJohn Forte 		    "status2=0x%x", status, status1, status2);
3763*fcf3ce44SJohn Forte 	}
3764*fcf3ce44SJohn Forte 
3765*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_ERROR);
3766*fcf3ce44SJohn Forte 
3767*fcf3ce44SJohn Forte 	if (status & HS_FFER6) {
3768*fcf3ce44SJohn Forte 		(void) thread_create(NULL, 0, emlxs_restart_thread,
3769*fcf3ce44SJohn Forte 		    (char *)hba, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
3770*fcf3ce44SJohn Forte 	} else {
3771*fcf3ce44SJohn Forte 		(void) thread_create(NULL, 0, emlxs_shutdown_thread,
3772*fcf3ce44SJohn Forte 		    (char *)hba, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
3773*fcf3ce44SJohn Forte 	}
3774*fcf3ce44SJohn Forte 
3775*fcf3ce44SJohn Forte } /* emlxs_handle_ff_error() */
3776*fcf3ce44SJohn Forte 
3777*fcf3ce44SJohn Forte 
3778*fcf3ce44SJohn Forte 
3779*fcf3ce44SJohn Forte extern void
3780*fcf3ce44SJohn Forte emlxs_reset_link_thread(void *arg)
3781*fcf3ce44SJohn Forte {
3782*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg;
3783*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3784*fcf3ce44SJohn Forte 
3785*fcf3ce44SJohn Forte 	/* Attempt a link reset to recover */
3786*fcf3ce44SJohn Forte 	(void) emlxs_reset(port, FC_FCA_LINK_RESET);
3787*fcf3ce44SJohn Forte 
3788*fcf3ce44SJohn Forte 	(void) thread_exit();
3789*fcf3ce44SJohn Forte 
3790*fcf3ce44SJohn Forte } /* emlxs_reset_link_thread() */
3791*fcf3ce44SJohn Forte 
3792*fcf3ce44SJohn Forte 
3793*fcf3ce44SJohn Forte extern void
3794*fcf3ce44SJohn Forte emlxs_restart_thread(void *arg)
3795*fcf3ce44SJohn Forte {
3796*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg;
3797*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3798*fcf3ce44SJohn Forte 
3799*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Restarting...");
3800*fcf3ce44SJohn Forte 
3801*fcf3ce44SJohn Forte 	/* Attempt a full hardware reset to recover */
3802*fcf3ce44SJohn Forte 	if (emlxs_reset(port, FC_FCA_RESET) != FC_SUCCESS) {
3803*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
3804*fcf3ce44SJohn Forte 
3805*fcf3ce44SJohn Forte 		(void) thread_create(NULL, 0, emlxs_shutdown_thread,
3806*fcf3ce44SJohn Forte 		    (char *)hba, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
3807*fcf3ce44SJohn Forte 	}
3808*fcf3ce44SJohn Forte 	(void) thread_exit();
3809*fcf3ce44SJohn Forte 
3810*fcf3ce44SJohn Forte } /* emlxs_restart_thread() */
3811*fcf3ce44SJohn Forte 
3812*fcf3ce44SJohn Forte 
3813*fcf3ce44SJohn Forte extern void
3814*fcf3ce44SJohn Forte emlxs_shutdown_thread(void *arg)
3815*fcf3ce44SJohn Forte {
3816*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg;
3817*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3818*fcf3ce44SJohn Forte 
3819*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
3820*fcf3ce44SJohn Forte 	if (hba->flag & FC_SHUTDOWN) {
3821*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
3822*fcf3ce44SJohn Forte 		(void) thread_exit();
3823*fcf3ce44SJohn Forte 	}
3824*fcf3ce44SJohn Forte 	hba->flag |= FC_SHUTDOWN;
3825*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
3826*fcf3ce44SJohn Forte 
3827*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Shutting down...");
3828*fcf3ce44SJohn Forte 
3829*fcf3ce44SJohn Forte 	/* Take adapter offline and leave it there */
3830*fcf3ce44SJohn Forte 	(void) emlxs_offline(hba);
3831*fcf3ce44SJohn Forte 
3832*fcf3ce44SJohn Forte 	/* Log a dump event */
3833*fcf3ce44SJohn Forte 	emlxs_log_dump_event(port, NULL, 0);
3834*fcf3ce44SJohn Forte 
3835*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_shutdown_msg, "Reboot required.");
3836*fcf3ce44SJohn Forte 
3837*fcf3ce44SJohn Forte 	(void) thread_exit();
3838*fcf3ce44SJohn Forte 
3839*fcf3ce44SJohn Forte } /* emlxs_shutdown_thread() */
3840*fcf3ce44SJohn Forte 
3841*fcf3ce44SJohn Forte 
3842*fcf3ce44SJohn Forte 
3843*fcf3ce44SJohn Forte /*
3844*fcf3ce44SJohn Forte  *  emlxs_handle_link_event
3845*fcf3ce44SJohn Forte  *
3846*fcf3ce44SJohn Forte  *    Description: Process a Link Attention.
3847*fcf3ce44SJohn Forte  *
3848*fcf3ce44SJohn Forte  */
3849*fcf3ce44SJohn Forte static void
3850*fcf3ce44SJohn Forte emlxs_handle_link_event(emlxs_hba_t *hba)
3851*fcf3ce44SJohn Forte {
3852*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3853*fcf3ce44SJohn Forte 	MAILBOX *mb;
3854*fcf3ce44SJohn Forte 
3855*fcf3ce44SJohn Forte 	HBASTATS.LinkEvent++;
3856*fcf3ce44SJohn Forte 
3857*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_event_msg,
3858*fcf3ce44SJohn Forte 	    "event=%x", HBASTATS.LinkEvent);
3859*fcf3ce44SJohn Forte 
3860*fcf3ce44SJohn Forte 
3861*fcf3ce44SJohn Forte 	/* Get a buffer which will be used for mailbox commands */
3862*fcf3ce44SJohn Forte 	if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
3863*fcf3ce44SJohn Forte 		/* Get link attention message */
3864*fcf3ce44SJohn Forte 		if (emlxs_mb_read_la(hba, mb) == 0) {
3865*fcf3ce44SJohn Forte 			if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) !=
3866*fcf3ce44SJohn Forte 			    MBX_BUSY) {
3867*fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_MBOX,
3868*fcf3ce44SJohn Forte 				    (uint8_t *)mb);
3869*fcf3ce44SJohn Forte 			}
3870*fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_PORT_LOCK);
3871*fcf3ce44SJohn Forte 
3872*fcf3ce44SJohn Forte 
3873*fcf3ce44SJohn Forte 			/*
3874*fcf3ce44SJohn Forte 			 * Clear Link Attention in HA REG
3875*fcf3ce44SJohn Forte 			 */
3876*fcf3ce44SJohn Forte 			WRITE_CSR_REG(hba,
3877*fcf3ce44SJohn Forte 			    FC_HA_REG(hba, hba->csr_addr), HA_LATT);
3878*fcf3ce44SJohn Forte 
3879*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
3880*fcf3ce44SJohn Forte 		} else {
3881*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
3882*fcf3ce44SJohn Forte 		}
3883*fcf3ce44SJohn Forte 	}
3884*fcf3ce44SJohn Forte } /* emlxs_handle_link_event()  */
3885*fcf3ce44SJohn Forte 
3886*fcf3ce44SJohn Forte 
3887*fcf3ce44SJohn Forte /*
3888*fcf3ce44SJohn Forte  *  emlxs_handle_ring_event
3889*fcf3ce44SJohn Forte  *
3890*fcf3ce44SJohn Forte  *    Description: Process a Ring Attention.
3891*fcf3ce44SJohn Forte  *
3892*fcf3ce44SJohn Forte  */
3893*fcf3ce44SJohn Forte static void
3894*fcf3ce44SJohn Forte emlxs_handle_ring_event(emlxs_hba_t *hba, int32_t ring_no, uint32_t ha_copy)
3895*fcf3ce44SJohn Forte {
3896*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3897*fcf3ce44SJohn Forte 	RING *rp;
3898*fcf3ce44SJohn Forte 	IOCB *entry;
3899*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3900*fcf3ce44SJohn Forte 	IOCBQ local_iocbq;
3901*fcf3ce44SJohn Forte 	PGP *pgp;
3902*fcf3ce44SJohn Forte 	uint32_t count;
3903*fcf3ce44SJohn Forte 	volatile uint32_t chipatt;
3904*fcf3ce44SJohn Forte 	void *ioa2;
3905*fcf3ce44SJohn Forte 	uint32_t reg;
3906*fcf3ce44SJohn Forte 	off_t offset;
3907*fcf3ce44SJohn Forte 	IOCBQ *rsp_head = NULL;
3908*fcf3ce44SJohn Forte 	IOCBQ *rsp_tail = NULL;
3909*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3910*fcf3ce44SJohn Forte 
3911*fcf3ce44SJohn Forte 	count = 0;
3912*fcf3ce44SJohn Forte 	rp = &hba->ring[ring_no];
3913*fcf3ce44SJohn Forte 
3914*fcf3ce44SJohn Forte 	/* Isolate this ring's host attention bits */
3915*fcf3ce44SJohn Forte 	/* This makes all ring attention bits equal to Ring0 attention bits */
3916*fcf3ce44SJohn Forte 	reg = (ha_copy >> (ring_no * 4)) & 0x0f;
3917*fcf3ce44SJohn Forte 
3918*fcf3ce44SJohn Forte 	/*
3919*fcf3ce44SJohn Forte 	 * Gather iocb entries off response ring. Ensure entry is owned by
3920*fcf3ce44SJohn Forte 	 * the host.
3921*fcf3ce44SJohn Forte 	 */
3922*fcf3ce44SJohn Forte 	pgp = (PGP *) & ((SLIM2 *) hba->slim2.virt)->mbx.us.s2.port[ring_no];
3923*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)&(pgp->rspPutInx) -
3924*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
3925*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
3926*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
3927*fcf3ce44SJohn Forte 	rp->fc_port_rspidx = PCIMEM_LONG(pgp->rspPutInx);
3928*fcf3ce44SJohn Forte 
3929*fcf3ce44SJohn Forte 	/* While ring is not empty */
3930*fcf3ce44SJohn Forte 	while (rp->fc_rspidx != rp->fc_port_rspidx) {
3931*fcf3ce44SJohn Forte 		HBASTATS.IocbReceived[ring_no]++;
3932*fcf3ce44SJohn Forte 
3933*fcf3ce44SJohn Forte 		/* Get the next response ring iocb */
3934*fcf3ce44SJohn Forte 		entry = (IOCB *) (((char *)rp->fc_rspringaddr +
3935*fcf3ce44SJohn Forte 		    (rp->fc_rspidx * hba->iocb_rsp_size)));
3936*fcf3ce44SJohn Forte 
3937*fcf3ce44SJohn Forte 		/* DMA sync the response ring iocb for the adapter */
3938*fcf3ce44SJohn Forte 		offset = (off_t)((uint64_t)(unsigned long)entry -
3939*fcf3ce44SJohn Forte 		    (uint64_t)(unsigned long)hba->slim2.virt);
3940*fcf3ce44SJohn Forte 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
3941*fcf3ce44SJohn Forte 		    hba->iocb_rsp_size, DDI_DMA_SYNC_FORKERNEL);
3942*fcf3ce44SJohn Forte 
3943*fcf3ce44SJohn Forte 		count++;
3944*fcf3ce44SJohn Forte 
3945*fcf3ce44SJohn Forte 		/* Copy word6 and word7 to local iocb for now */
3946*fcf3ce44SJohn Forte 		iocbq = &local_iocbq;
3947*fcf3ce44SJohn Forte 		emlxs_pcimem_bcopy((uint32_t *)entry + 6, (uint32_t *)iocbq + 6,
3948*fcf3ce44SJohn Forte 		    (sizeof (uint32_t) * 2));
3949*fcf3ce44SJohn Forte 
3950*fcf3ce44SJohn Forte 		/* when LE is not set, entire Command has not been received */
3951*fcf3ce44SJohn Forte 		if (!iocbq->iocb.ulpLe) {
3952*fcf3ce44SJohn Forte 			/* This should never happen */
3953*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ring_error_msg,
3954*fcf3ce44SJohn Forte 			    "ulpLE is not set. ring=%d iotag=%x cmd=%x "
3955*fcf3ce44SJohn Forte 			    "status=%x", ring_no, iocbq->iocb.ulpIoTag,
3956*fcf3ce44SJohn Forte 			    iocbq->iocb.ulpCommand, iocbq->iocb.ulpStatus);
3957*fcf3ce44SJohn Forte 
3958*fcf3ce44SJohn Forte 			goto next;
3959*fcf3ce44SJohn Forte 		}
3960*fcf3ce44SJohn Forte 		switch (iocbq->iocb.ulpCommand) {
3961*fcf3ce44SJohn Forte 			/* Ring 0 registered commands */
3962*fcf3ce44SJohn Forte 		case CMD_FCP_ICMND_CR:
3963*fcf3ce44SJohn Forte 		case CMD_FCP_ICMND_CX:
3964*fcf3ce44SJohn Forte 		case CMD_FCP_IREAD_CR:
3965*fcf3ce44SJohn Forte 		case CMD_FCP_IREAD_CX:
3966*fcf3ce44SJohn Forte 		case CMD_FCP_IWRITE_CR:
3967*fcf3ce44SJohn Forte 		case CMD_FCP_IWRITE_CX:
3968*fcf3ce44SJohn Forte 		case CMD_FCP_ICMND64_CR:
3969*fcf3ce44SJohn Forte 		case CMD_FCP_ICMND64_CX:
3970*fcf3ce44SJohn Forte 		case CMD_FCP_IREAD64_CR:
3971*fcf3ce44SJohn Forte 		case CMD_FCP_IREAD64_CX:
3972*fcf3ce44SJohn Forte 		case CMD_FCP_IWRITE64_CR:
3973*fcf3ce44SJohn Forte 		case CMD_FCP_IWRITE64_CX:
3974*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
3975*fcf3ce44SJohn Forte 		case CMD_FCP_TSEND_CX:
3976*fcf3ce44SJohn Forte 		case CMD_FCP_TSEND64_CX:
3977*fcf3ce44SJohn Forte 		case CMD_FCP_TRECEIVE_CX:
3978*fcf3ce44SJohn Forte 		case CMD_FCP_TRECEIVE64_CX:
3979*fcf3ce44SJohn Forte 		case CMD_FCP_TRSP_CX:
3980*fcf3ce44SJohn Forte 		case CMD_FCP_TRSP64_CX:
3981*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
3982*fcf3ce44SJohn Forte 
3983*fcf3ce44SJohn Forte 			/* Ring 1 registered commands */
3984*fcf3ce44SJohn Forte 		case CMD_XMIT_BCAST_CN:
3985*fcf3ce44SJohn Forte 		case CMD_XMIT_BCAST_CX:
3986*fcf3ce44SJohn Forte 		case CMD_XMIT_SEQUENCE_CX:
3987*fcf3ce44SJohn Forte 		case CMD_XMIT_SEQUENCE_CR:
3988*fcf3ce44SJohn Forte 		case CMD_XMIT_BCAST64_CN:
3989*fcf3ce44SJohn Forte 		case CMD_XMIT_BCAST64_CX:
3990*fcf3ce44SJohn Forte 		case CMD_XMIT_SEQUENCE64_CX:
3991*fcf3ce44SJohn Forte 		case CMD_XMIT_SEQUENCE64_CR:
3992*fcf3ce44SJohn Forte 		case CMD_CREATE_XRI_CR:
3993*fcf3ce44SJohn Forte 		case CMD_CREATE_XRI_CX:
3994*fcf3ce44SJohn Forte 
3995*fcf3ce44SJohn Forte 			/* Ring 2 registered commands */
3996*fcf3ce44SJohn Forte 		case CMD_ELS_REQUEST_CR:
3997*fcf3ce44SJohn Forte 		case CMD_ELS_REQUEST_CX:
3998*fcf3ce44SJohn Forte 		case CMD_XMIT_ELS_RSP_CX:
3999*fcf3ce44SJohn Forte 		case CMD_ELS_REQUEST64_CR:
4000*fcf3ce44SJohn Forte 		case CMD_ELS_REQUEST64_CX:
4001*fcf3ce44SJohn Forte 		case CMD_XMIT_ELS_RSP64_CX:
4002*fcf3ce44SJohn Forte 
4003*fcf3ce44SJohn Forte 			/* Ring 3 registered commands */
4004*fcf3ce44SJohn Forte 		case CMD_GEN_REQUEST64_CR:
4005*fcf3ce44SJohn Forte 		case CMD_GEN_REQUEST64_CX:
4006*fcf3ce44SJohn Forte 
4007*fcf3ce44SJohn Forte 			sbp = emlxs_unregister_pkt(rp, iocbq->iocb.ulpIoTag, 0);
4008*fcf3ce44SJohn Forte 			break;
4009*fcf3ce44SJohn Forte 
4010*fcf3ce44SJohn Forte 		default:
4011*fcf3ce44SJohn Forte 			sbp = NULL;
4012*fcf3ce44SJohn Forte 		}
4013*fcf3ce44SJohn Forte 
4014*fcf3ce44SJohn Forte 		/* If packet is stale, then drop it. */
4015*fcf3ce44SJohn Forte 		if (sbp == STALE_PACKET) {
4016*fcf3ce44SJohn Forte 			/* Copy entry to the local iocbq */
4017*fcf3ce44SJohn Forte 			emlxs_pcimem_bcopy((uint32_t *)entry, (uint32_t *)iocbq,
4018*fcf3ce44SJohn Forte 			    hba->iocb_rsp_size);
4019*fcf3ce44SJohn Forte 
4020*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_stale_msg,
4021*fcf3ce44SJohn Forte 			    "ringno=%d iocb=%p cmd=%x status=%x error=%x "
4022*fcf3ce44SJohn Forte 			    "iotag=%x context=%x info=%x", ring_no, iocbq,
4023*fcf3ce44SJohn Forte 			    (uint8_t)iocbq->iocb.ulpCommand,
4024*fcf3ce44SJohn Forte 			    iocbq->iocb.ulpStatus,
4025*fcf3ce44SJohn Forte 			    (uint8_t)iocbq->iocb.un.grsp.perr.statLocalError,
4026*fcf3ce44SJohn Forte 			    (uint16_t)iocbq->iocb.ulpIoTag,
4027*fcf3ce44SJohn Forte 			    (uint16_t)iocbq->iocb.ulpContext,
4028*fcf3ce44SJohn Forte 			    (uint8_t)iocbq->iocb.ulpRsvdByte);
4029*fcf3ce44SJohn Forte 
4030*fcf3ce44SJohn Forte 			goto next;
4031*fcf3ce44SJohn Forte 		}
4032*fcf3ce44SJohn Forte 		/*
4033*fcf3ce44SJohn Forte 		 * If a packet was found, then queue the packet's iocb for
4034*fcf3ce44SJohn Forte 		 * deferred processing
4035*fcf3ce44SJohn Forte 		 */
4036*fcf3ce44SJohn Forte 		else if (sbp) {
4037*fcf3ce44SJohn Forte 			atomic_add_32(&hba->io_active, -1);
4038*fcf3ce44SJohn Forte 
4039*fcf3ce44SJohn Forte 			/* Copy entry to sbp's iocbq */
4040*fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
4041*fcf3ce44SJohn Forte 			emlxs_pcimem_bcopy((uint32_t *)entry, (uint32_t *)iocbq,
4042*fcf3ce44SJohn Forte 			    hba->iocb_rsp_size);
4043*fcf3ce44SJohn Forte 
4044*fcf3ce44SJohn Forte 			iocbq->next = NULL;
4045*fcf3ce44SJohn Forte 
4046*fcf3ce44SJohn Forte 			/*
4047*fcf3ce44SJohn Forte 			 * If this is NOT a polled command completion or a
4048*fcf3ce44SJohn Forte 			 * driver allocated pkt, then defer pkt completion.
4049*fcf3ce44SJohn Forte 			 */
4050*fcf3ce44SJohn Forte 			if (!(sbp->pkt_flags & PACKET_POLLED |
4051*fcf3ce44SJohn Forte 			    PACKET_ALLOCATED)) {
4052*fcf3ce44SJohn Forte 				/* Add the IOCB to the local list */
4053*fcf3ce44SJohn Forte 				if (!rsp_head) {
4054*fcf3ce44SJohn Forte 					rsp_head = iocbq;
4055*fcf3ce44SJohn Forte 				} else {
4056*fcf3ce44SJohn Forte 					rsp_tail->next = iocbq;
4057*fcf3ce44SJohn Forte 				}
4058*fcf3ce44SJohn Forte 
4059*fcf3ce44SJohn Forte 				rsp_tail = iocbq;
4060*fcf3ce44SJohn Forte 
4061*fcf3ce44SJohn Forte 				goto next;
4062*fcf3ce44SJohn Forte 			}
4063*fcf3ce44SJohn Forte 		} else {
4064*fcf3ce44SJohn Forte 			/* Copy entry to the local iocbq */
4065*fcf3ce44SJohn Forte 			emlxs_pcimem_bcopy((uint32_t *)entry, (uint32_t *)iocbq,
4066*fcf3ce44SJohn Forte 			    hba->iocb_rsp_size);
4067*fcf3ce44SJohn Forte 
4068*fcf3ce44SJohn Forte 			iocbq->next = NULL;
4069*fcf3ce44SJohn Forte 			iocbq->bp = NULL;
4070*fcf3ce44SJohn Forte 			iocbq->port = &PPORT;
4071*fcf3ce44SJohn Forte 			iocbq->ring = rp;
4072*fcf3ce44SJohn Forte 			iocbq->node = NULL;
4073*fcf3ce44SJohn Forte 			iocbq->sbp = NULL;
4074*fcf3ce44SJohn Forte 			iocbq->flag = 0;
4075*fcf3ce44SJohn Forte 		}
4076*fcf3ce44SJohn Forte 
4077*fcf3ce44SJohn Forte 		/* process the ring event now */
4078*fcf3ce44SJohn Forte 		emlxs_proc_ring_event(hba, rp, iocbq);
4079*fcf3ce44SJohn Forte 
4080*fcf3ce44SJohn Forte next:
4081*fcf3ce44SJohn Forte 		/* Increment the driver's local response get index */
4082*fcf3ce44SJohn Forte 		if (++rp->fc_rspidx >= rp->fc_numRiocb) {
4083*fcf3ce44SJohn Forte 			rp->fc_rspidx = 0;
4084*fcf3ce44SJohn Forte 		}
4085*fcf3ce44SJohn Forte 	}	/* while(TRUE) */
4086*fcf3ce44SJohn Forte 
4087*fcf3ce44SJohn Forte 	if (rsp_head) {
4088*fcf3ce44SJohn Forte 		mutex_enter(&rp->rsp_lock);
4089*fcf3ce44SJohn Forte 		if (rp->rsp_head == NULL) {
4090*fcf3ce44SJohn Forte 			rp->rsp_head = rsp_head;
4091*fcf3ce44SJohn Forte 			rp->rsp_tail = rsp_tail;
4092*fcf3ce44SJohn Forte 		} else {
4093*fcf3ce44SJohn Forte 			rp->rsp_tail->next = rsp_head;
4094*fcf3ce44SJohn Forte 			rp->rsp_tail = rsp_tail;
4095*fcf3ce44SJohn Forte 		}
4096*fcf3ce44SJohn Forte 		mutex_exit(&rp->rsp_lock);
4097*fcf3ce44SJohn Forte 
4098*fcf3ce44SJohn Forte 		emlxs_thread_trigger2(&rp->intr_thread, emlxs_proc_ring, rp);
4099*fcf3ce44SJohn Forte 	}
4100*fcf3ce44SJohn Forte 	/* Check if at least one response entry was processed */
4101*fcf3ce44SJohn Forte 	if (count) {
4102*fcf3ce44SJohn Forte 		/* Update response get index for the adapter */
4103*fcf3ce44SJohn Forte 		if (hba->bus_type == SBUS_FC) {
4104*fcf3ce44SJohn Forte 			((SLIM2 *) hba->slim2.virt)->mbx.us.s2.host[ring_no].
4105*fcf3ce44SJohn Forte 			    rspGetInx = PCIMEM_LONG(rp->fc_rspidx);
4106*fcf3ce44SJohn Forte 
4107*fcf3ce44SJohn Forte 			/* DMA sync the index for the adapter */
4108*fcf3ce44SJohn Forte 			offset = (off_t)((uint64_t)(unsigned long)&((
4109*fcf3ce44SJohn Forte 			    (SLIM2 *)hba->slim2.virt)->mbx.us.s2.host[ring_no].
4110*fcf3ce44SJohn Forte 			    rspGetInx) -
4111*fcf3ce44SJohn Forte 			    (uint64_t)(unsigned long)hba->slim2.virt);
4112*fcf3ce44SJohn Forte 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4113*fcf3ce44SJohn Forte 			    DDI_DMA_SYNC_FORDEV);
4114*fcf3ce44SJohn Forte 		} else {
4115*fcf3ce44SJohn Forte 			ioa2 = (void *) ((char *)hba->slim_addr +
4116*fcf3ce44SJohn Forte 			    hba->hgp_ring_offset + (((ring_no * 2) + 1) *
4117*fcf3ce44SJohn Forte 			    sizeof (uint32_t)));
4118*fcf3ce44SJohn Forte 			WRITE_SLIM_ADDR(hba, (volatile uint32_t *) ioa2,
4119*fcf3ce44SJohn Forte 			    rp->fc_rspidx);
4120*fcf3ce44SJohn Forte 		}
4121*fcf3ce44SJohn Forte 
4122*fcf3ce44SJohn Forte 		if (reg & HA_R0RE_REQ) {
4123*fcf3ce44SJohn Forte 			/* HBASTATS.chipRingFree++; */
4124*fcf3ce44SJohn Forte 
4125*fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_PORT_LOCK);
4126*fcf3ce44SJohn Forte 
4127*fcf3ce44SJohn Forte 			/* Tell the adapter we serviced the ring */
4128*fcf3ce44SJohn Forte 			chipatt = ((CA_R0ATT | CA_R0RE_RSP) <<
4129*fcf3ce44SJohn Forte 			    (ring_no * 4));
4130*fcf3ce44SJohn Forte 			WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr),
4131*fcf3ce44SJohn Forte 			    chipatt);
4132*fcf3ce44SJohn Forte 
4133*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
4134*fcf3ce44SJohn Forte 		}
4135*fcf3ce44SJohn Forte 	}
4136*fcf3ce44SJohn Forte 	if (reg & HA_R0CE_RSP) {
4137*fcf3ce44SJohn Forte 		/* HBASTATS.hostRingFree++; */
4138*fcf3ce44SJohn Forte 
4139*fcf3ce44SJohn Forte 		/* Cmd ring may be available. Try sending more iocbs */
4140*fcf3ce44SJohn Forte 		emlxs_issue_iocb_cmd(hba, rp, 0);
4141*fcf3ce44SJohn Forte 	}
4142*fcf3ce44SJohn Forte 	/* HBASTATS.ringEvent++; */
4143*fcf3ce44SJohn Forte 
4144*fcf3ce44SJohn Forte 	return;
4145*fcf3ce44SJohn Forte 
4146*fcf3ce44SJohn Forte } /* emlxs_handle_ring_event() */
4147*fcf3ce44SJohn Forte 
4148*fcf3ce44SJohn Forte 
4149*fcf3ce44SJohn Forte /* ARGSUSED */
4150*fcf3ce44SJohn Forte extern void
4151*fcf3ce44SJohn Forte emlxs_proc_ring(emlxs_hba_t *hba, RING *rp, void *arg2)
4152*fcf3ce44SJohn Forte {
4153*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4154*fcf3ce44SJohn Forte 	IOCBQ *rsp_head;
4155*fcf3ce44SJohn Forte 
4156*fcf3ce44SJohn Forte 	/*
4157*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, "emlxs_proc_ring:
4158*fcf3ce44SJohn Forte 	 * ringo=%d", rp->ringno);
4159*fcf3ce44SJohn Forte 	 */
4160*fcf3ce44SJohn Forte 
4161*fcf3ce44SJohn Forte 	mutex_enter(&rp->rsp_lock);
4162*fcf3ce44SJohn Forte 
4163*fcf3ce44SJohn Forte 	while ((rsp_head = rp->rsp_head) != NULL) {
4164*fcf3ce44SJohn Forte 		rp->rsp_head = NULL;
4165*fcf3ce44SJohn Forte 		rp->rsp_tail = NULL;
4166*fcf3ce44SJohn Forte 
4167*fcf3ce44SJohn Forte 		mutex_exit(&rp->rsp_lock);
4168*fcf3ce44SJohn Forte 
4169*fcf3ce44SJohn Forte 		while ((iocbq = rsp_head) != NULL) {
4170*fcf3ce44SJohn Forte 			rsp_head = (IOCBQ *) iocbq->next;
4171*fcf3ce44SJohn Forte 
4172*fcf3ce44SJohn Forte 			emlxs_proc_ring_event(hba, rp, iocbq);
4173*fcf3ce44SJohn Forte 		}
4174*fcf3ce44SJohn Forte 
4175*fcf3ce44SJohn Forte 		mutex_enter(&rp->rsp_lock);
4176*fcf3ce44SJohn Forte 	}
4177*fcf3ce44SJohn Forte 
4178*fcf3ce44SJohn Forte 	mutex_exit(&rp->rsp_lock);
4179*fcf3ce44SJohn Forte 
4180*fcf3ce44SJohn Forte 	emlxs_issue_iocb_cmd(hba, rp, 0);
4181*fcf3ce44SJohn Forte 
4182*fcf3ce44SJohn Forte 	return;
4183*fcf3ce44SJohn Forte 
4184*fcf3ce44SJohn Forte } /* emlxs_proc_ring() */
4185*fcf3ce44SJohn Forte 
4186*fcf3ce44SJohn Forte 
4187*fcf3ce44SJohn Forte /*
4188*fcf3ce44SJohn Forte  * Called from SLI-1 and SLI-2 ring event routines to process a rsp ring IOCB.
4189*fcf3ce44SJohn Forte  */
4190*fcf3ce44SJohn Forte static void
4191*fcf3ce44SJohn Forte emlxs_proc_ring_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
4192*fcf3ce44SJohn Forte {
4193*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
4194*fcf3ce44SJohn Forte 	char buffer[MAX_MSG_DATA + 1];
4195*fcf3ce44SJohn Forte 	IOCB *iocb;
4196*fcf3ce44SJohn Forte 
4197*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
4198*fcf3ce44SJohn Forte 
4199*fcf3ce44SJohn Forte 	/* Check for IOCB local error */
4200*fcf3ce44SJohn Forte 	if (iocb->ulpStatus == IOSTAT_LOCAL_REJECT) {
4201*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_event_msg,
4202*fcf3ce44SJohn Forte 		    "Local reject. ringno=%d iocb=%p cmd=%x iotag=%x "
4203*fcf3ce44SJohn Forte 		    "context=%x info=%x error=%x",
4204*fcf3ce44SJohn Forte 		    rp->ringno, iocb, (uint8_t)iocb->ulpCommand,
4205*fcf3ce44SJohn Forte 		    (uint16_t)iocb->ulpIoTag, (uint16_t)iocb->ulpContext,
4206*fcf3ce44SJohn Forte 		    (uint8_t)iocb->ulpRsvdByte,
4207*fcf3ce44SJohn Forte 		    (uint8_t)iocb->un.grsp.perr.statLocalError);
4208*fcf3ce44SJohn Forte 	} else if (iocb->ulpStatus == IOSTAT_ILLEGAL_FRAME_RCVD) {
4209*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_event_msg,
4210*fcf3ce44SJohn Forte 		    "Illegal frame. ringno=%d iocb=%p cmd=%x iotag=%x "
4211*fcf3ce44SJohn Forte 		    "context=%x info=%x error=%x",
4212*fcf3ce44SJohn Forte 		    rp->ringno, iocb, (uint8_t)iocb->ulpCommand,
4213*fcf3ce44SJohn Forte 		    (uint16_t)iocb->ulpIoTag, (uint16_t)iocb->ulpContext,
4214*fcf3ce44SJohn Forte 		    (uint8_t)iocb->ulpRsvdByte,
4215*fcf3ce44SJohn Forte 		    (uint8_t)iocb->un.grsp.perr.statLocalError);
4216*fcf3ce44SJohn Forte 	}
4217*fcf3ce44SJohn Forte 	switch (iocb->ulpCommand) {
4218*fcf3ce44SJohn Forte 		/* RING 0 FCP commands */
4219*fcf3ce44SJohn Forte 	case CMD_FCP_ICMND_CR:
4220*fcf3ce44SJohn Forte 	case CMD_FCP_ICMND_CX:
4221*fcf3ce44SJohn Forte 	case CMD_FCP_IREAD_CR:
4222*fcf3ce44SJohn Forte 	case CMD_FCP_IREAD_CX:
4223*fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE_CR:
4224*fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE_CX:
4225*fcf3ce44SJohn Forte 	case CMD_FCP_ICMND64_CR:
4226*fcf3ce44SJohn Forte 	case CMD_FCP_ICMND64_CX:
4227*fcf3ce44SJohn Forte 	case CMD_FCP_IREAD64_CR:
4228*fcf3ce44SJohn Forte 	case CMD_FCP_IREAD64_CX:
4229*fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE64_CR:
4230*fcf3ce44SJohn Forte 	case CMD_FCP_IWRITE64_CX:
4231*fcf3ce44SJohn Forte 		(void) emlxs_handle_fcp_event(hba, rp, iocbq);
4232*fcf3ce44SJohn Forte 		break;
4233*fcf3ce44SJohn Forte 
4234*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
4235*fcf3ce44SJohn Forte 	case CMD_FCP_TSEND_CX:	/* FCP_TARGET IOCB command */
4236*fcf3ce44SJohn Forte 	case CMD_FCP_TSEND64_CX:	/* FCP_TARGET IOCB command */
4237*fcf3ce44SJohn Forte 	case CMD_FCP_TRECEIVE_CX:	/* FCP_TARGET IOCB command */
4238*fcf3ce44SJohn Forte 	case CMD_FCP_TRECEIVE64_CX:	/* FCP_TARGET IOCB command */
4239*fcf3ce44SJohn Forte 	case CMD_FCP_TRSP_CX:	/* FCP_TARGET IOCB command */
4240*fcf3ce44SJohn Forte 	case CMD_FCP_TRSP64_CX:	/* FCP_TARGET IOCB command */
4241*fcf3ce44SJohn Forte 		(void) emlxs_fct_handle_fcp_event(hba, rp, iocbq);
4242*fcf3ce44SJohn Forte 		break;
4243*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
4244*fcf3ce44SJohn Forte 
4245*fcf3ce44SJohn Forte 		/* RING 1 IP commands */
4246*fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST_CN:
4247*fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST_CX:
4248*fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST64_CN:
4249*fcf3ce44SJohn Forte 	case CMD_XMIT_BCAST64_CX:
4250*fcf3ce44SJohn Forte 		(void) emlxs_ip_handle_event(hba, rp, iocbq);
4251*fcf3ce44SJohn Forte 		break;
4252*fcf3ce44SJohn Forte 
4253*fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE_CX:
4254*fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE_CR:
4255*fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE64_CX:
4256*fcf3ce44SJohn Forte 	case CMD_XMIT_SEQUENCE64_CR:
4257*fcf3ce44SJohn Forte 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
4258*fcf3ce44SJohn Forte 		case FC_TYPE_IS8802_SNAP:
4259*fcf3ce44SJohn Forte 			(void) emlxs_ip_handle_event(hba, rp, iocbq);
4260*fcf3ce44SJohn Forte 			break;
4261*fcf3ce44SJohn Forte 
4262*fcf3ce44SJohn Forte 		case FC_TYPE_FC_SERVICES:
4263*fcf3ce44SJohn Forte 			(void) emlxs_ct_handle_event(hba, rp, iocbq);
4264*fcf3ce44SJohn Forte 			break;
4265*fcf3ce44SJohn Forte 
4266*fcf3ce44SJohn Forte 		default:
4267*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
4268*fcf3ce44SJohn Forte 			    "cmd=%x type=%x status=%x iotag=%x context=%x ",
4269*fcf3ce44SJohn Forte 			    iocb->ulpCommand, iocb->un.rcvseq64.w5.hcsw.Type,
4270*fcf3ce44SJohn Forte 			    iocb->ulpStatus, iocb->ulpIoTag, iocb->ulpContext);
4271*fcf3ce44SJohn Forte 		}
4272*fcf3ce44SJohn Forte 		break;
4273*fcf3ce44SJohn Forte 
4274*fcf3ce44SJohn Forte 	case CMD_RCV_SEQUENCE_CX:
4275*fcf3ce44SJohn Forte 	case CMD_RCV_SEQUENCE64_CX:
4276*fcf3ce44SJohn Forte 	case CMD_RCV_SEQ64_CX:
4277*fcf3ce44SJohn Forte 	case CMD_RCV_ELS_REQ_CX:	/* Unsolicited ELS frame  */
4278*fcf3ce44SJohn Forte 	case CMD_RCV_ELS_REQ64_CX:	/* Unsolicited ELS frame  */
4279*fcf3ce44SJohn Forte 	case CMD_RCV_ELS64_CX:	/* Unsolicited ELS frame  */
4280*fcf3ce44SJohn Forte 		(void) emlxs_handle_rcv_seq(hba, rp, iocbq);
4281*fcf3ce44SJohn Forte 		break;
4282*fcf3ce44SJohn Forte 
4283*fcf3ce44SJohn Forte 	case CMD_RCV_SEQ_LIST64_CX:
4284*fcf3ce44SJohn Forte 		(void) emlxs_ip_handle_rcv_seq_list(hba, rp, iocbq);
4285*fcf3ce44SJohn Forte 		break;
4286*fcf3ce44SJohn Forte 
4287*fcf3ce44SJohn Forte 	case CMD_CREATE_XRI_CR:
4288*fcf3ce44SJohn Forte 	case CMD_CREATE_XRI_CX:
4289*fcf3ce44SJohn Forte 		(void) emlxs_handle_create_xri(hba, rp, iocbq);
4290*fcf3ce44SJohn Forte 		break;
4291*fcf3ce44SJohn Forte 
4292*fcf3ce44SJohn Forte 		/* RING 2 ELS commands */
4293*fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST_CR:
4294*fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST_CX:
4295*fcf3ce44SJohn Forte 	case CMD_XMIT_ELS_RSP_CX:
4296*fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST64_CR:
4297*fcf3ce44SJohn Forte 	case CMD_ELS_REQUEST64_CX:
4298*fcf3ce44SJohn Forte 	case CMD_XMIT_ELS_RSP64_CX:
4299*fcf3ce44SJohn Forte 		(void) emlxs_els_handle_event(hba, rp, iocbq);
4300*fcf3ce44SJohn Forte 		break;
4301*fcf3ce44SJohn Forte 
4302*fcf3ce44SJohn Forte 		/* RING 3 CT commands */
4303*fcf3ce44SJohn Forte 	case CMD_GEN_REQUEST64_CR:
4304*fcf3ce44SJohn Forte 	case CMD_GEN_REQUEST64_CX:
4305*fcf3ce44SJohn Forte 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
4306*fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
4307*fcf3ce44SJohn Forte 		case EMLXS_MENLO_TYPE:
4308*fcf3ce44SJohn Forte 			(void) emlxs_menlo_handle_event(hba, rp, iocbq);
4309*fcf3ce44SJohn Forte 			break;
4310*fcf3ce44SJohn Forte #endif	/* MENLO_SUPPORT */
4311*fcf3ce44SJohn Forte 
4312*fcf3ce44SJohn Forte 		case FC_TYPE_FC_SERVICES:
4313*fcf3ce44SJohn Forte 			(void) emlxs_ct_handle_event(hba, rp, iocbq);
4314*fcf3ce44SJohn Forte 			break;
4315*fcf3ce44SJohn Forte 
4316*fcf3ce44SJohn Forte 		default:
4317*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
4318*fcf3ce44SJohn Forte 			    "cmd=%x type=%x status=%x iotag=%x context=%x ",
4319*fcf3ce44SJohn Forte 			    iocb->ulpCommand, iocb->un.rcvseq64.w5.hcsw.Type,
4320*fcf3ce44SJohn Forte 			    iocb->ulpStatus, iocb->ulpIoTag, iocb->ulpContext);
4321*fcf3ce44SJohn Forte 		}
4322*fcf3ce44SJohn Forte 		break;
4323*fcf3ce44SJohn Forte 
4324*fcf3ce44SJohn Forte 	case CMD_ABORT_XRI_CN:	/* Abort fcp command */
4325*fcf3ce44SJohn Forte 
4326*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
4327*fcf3ce44SJohn Forte 		    "ABORT_XRI_CN: rpi=%d iotag=%x status=%x parm=%x",
4328*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
4329*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortIoTag,
4330*fcf3ce44SJohn Forte 		    iocb->ulpStatus, iocb->un.acxri.parm);
4331*fcf3ce44SJohn Forte 
4332*fcf3ce44SJohn Forte 		break;
4333*fcf3ce44SJohn Forte 
4334*fcf3ce44SJohn Forte 	case CMD_ABORT_XRI_CX:	/* Abort command */
4335*fcf3ce44SJohn Forte 
4336*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
4337*fcf3ce44SJohn Forte 		    "ABORT_XRI_CX: rpi=%d iotag=%x status=%x parm=%x",
4338*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
4339*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortIoTag,
4340*fcf3ce44SJohn Forte 		    iocb->ulpStatus, iocb->un.acxri.parm);
4341*fcf3ce44SJohn Forte 
4342*fcf3ce44SJohn Forte 		break;
4343*fcf3ce44SJohn Forte 
4344*fcf3ce44SJohn Forte 	case CMD_XRI_ABORTED_CX:	/* Handle ABORT condition */
4345*fcf3ce44SJohn Forte 
4346*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
4347*fcf3ce44SJohn Forte 		    "XRI_ABORTED_CX: rpi=%d iotag=%x status=%x parm=%x",
4348*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
4349*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortIoTag,
4350*fcf3ce44SJohn Forte 		    iocb->ulpStatus, iocb->un.acxri.parm);
4351*fcf3ce44SJohn Forte 
4352*fcf3ce44SJohn Forte 		break;
4353*fcf3ce44SJohn Forte 
4354*fcf3ce44SJohn Forte 	case CMD_CLOSE_XRI_CN:	/* Handle CLOSE condition */
4355*fcf3ce44SJohn Forte 
4356*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
4357*fcf3ce44SJohn Forte 		    "CLOSE_XRI_CR: rpi=%d iotag=%x status=%x parm=%x",
4358*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
4359*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortIoTag,
4360*fcf3ce44SJohn Forte 		    iocb->ulpStatus, iocb->un.acxri.parm);
4361*fcf3ce44SJohn Forte 
4362*fcf3ce44SJohn Forte 		break;
4363*fcf3ce44SJohn Forte 
4364*fcf3ce44SJohn Forte 	case CMD_CLOSE_XRI_CX:	/* Handle CLOSE condition */
4365*fcf3ce44SJohn Forte 
4366*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
4367*fcf3ce44SJohn Forte 		    "CLOSE_XRI_CX: rpi=%d iotag=%x status=%x parm=%x",
4368*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortContextTag,
4369*fcf3ce44SJohn Forte 		    (uint32_t)iocb->un.acxri.abortIoTag,
4370*fcf3ce44SJohn Forte 		    iocb->ulpStatus, iocb->un.acxri.parm);
4371*fcf3ce44SJohn Forte 
4372*fcf3ce44SJohn Forte 		break;
4373*fcf3ce44SJohn Forte 
4374*fcf3ce44SJohn Forte 	case CMD_ADAPTER_MSG:
4375*fcf3ce44SJohn Forte 		/* Allows debug adapter firmware messages to print on host */
4376*fcf3ce44SJohn Forte 		bzero(buffer, sizeof (buffer));
4377*fcf3ce44SJohn Forte 		bcopy((uint8_t *)iocb, buffer, MAX_MSG_DATA);
4378*fcf3ce44SJohn Forte 
4379*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_msg, "%s", buffer);
4380*fcf3ce44SJohn Forte 
4381*fcf3ce44SJohn Forte 		break;
4382*fcf3ce44SJohn Forte 
4383*fcf3ce44SJohn Forte 	case CMD_QUE_RING_LIST64_CN:
4384*fcf3ce44SJohn Forte 	case CMD_QUE_RING_BUF64_CN:
4385*fcf3ce44SJohn Forte 		break;
4386*fcf3ce44SJohn Forte 
4387*fcf3ce44SJohn Forte 	case CMD_ASYNC_STATUS:
4388*fcf3ce44SJohn Forte 		(void) emlxs_handle_async_event(hba, rp, iocbq);
4389*fcf3ce44SJohn Forte 		break;
4390*fcf3ce44SJohn Forte 
4391*fcf3ce44SJohn Forte 	default:
4392*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
4393*fcf3ce44SJohn Forte 		    "cmd=%x status=%x iotag=%x context=%x",
4394*fcf3ce44SJohn Forte 		    iocb->ulpCommand, iocb->ulpStatus, iocb->ulpIoTag,
4395*fcf3ce44SJohn Forte 		    iocb->ulpContext);
4396*fcf3ce44SJohn Forte 
4397*fcf3ce44SJohn Forte 		break;
4398*fcf3ce44SJohn Forte 	}	/* switch(entry->ulpCommand) */
4399*fcf3ce44SJohn Forte 
4400*fcf3ce44SJohn Forte 	return;
4401*fcf3ce44SJohn Forte 
4402*fcf3ce44SJohn Forte } /* emlxs_proc_ring_event() */
4403*fcf3ce44SJohn Forte 
4404*fcf3ce44SJohn Forte 
4405*fcf3ce44SJohn Forte 
4406*fcf3ce44SJohn Forte static int
4407*fcf3ce44SJohn Forte emlxs_handle_rcv_seq(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
4408*fcf3ce44SJohn Forte {
4409*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
4410*fcf3ce44SJohn Forte 	IOCB *iocb;
4411*fcf3ce44SJohn Forte 	MATCHMAP *mp = NULL;
4412*fcf3ce44SJohn Forte 	uint64_t bdeAddr;
4413*fcf3ce44SJohn Forte 	uint32_t vpi = 0;
4414*fcf3ce44SJohn Forte 	uint32_t ringno;
4415*fcf3ce44SJohn Forte 	uint32_t size = 0;
4416*fcf3ce44SJohn Forte 	uint32_t *RcvError;
4417*fcf3ce44SJohn Forte 	uint32_t *RcvDropped;
4418*fcf3ce44SJohn Forte 	uint32_t *UbPosted;
4419*fcf3ce44SJohn Forte 	emlxs_msg_t *dropped_msg;
4420*fcf3ce44SJohn Forte 	char error_str[64];
4421*fcf3ce44SJohn Forte 	uint32_t buf_type;
4422*fcf3ce44SJohn Forte 	uint32_t *word;
4423*fcf3ce44SJohn Forte 
4424*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
4425*fcf3ce44SJohn Forte 	uint32_t hbq_id;
4426*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
4427*fcf3ce44SJohn Forte 
4428*fcf3ce44SJohn Forte 	ringno = rp->ringno;
4429*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
4430*fcf3ce44SJohn Forte 	word = (uint32_t *)iocb;
4431*fcf3ce44SJohn Forte 
4432*fcf3ce44SJohn Forte 	switch (ringno) {
4433*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
4434*fcf3ce44SJohn Forte 	case FC_FCT_RING:
4435*fcf3ce44SJohn Forte 		HBASTATS.FctRingEvent++;
4436*fcf3ce44SJohn Forte 		RcvError = &HBASTATS.FctRingError;
4437*fcf3ce44SJohn Forte 		RcvDropped = &HBASTATS.FctRingDropped;
4438*fcf3ce44SJohn Forte 		UbPosted = &HBASTATS.FctUbPosted;
4439*fcf3ce44SJohn Forte 		dropped_msg = &emlxs_fct_detail_msg;
4440*fcf3ce44SJohn Forte 		buf_type = MEM_FCTBUF;
4441*fcf3ce44SJohn Forte 		break;
4442*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
4443*fcf3ce44SJohn Forte 
4444*fcf3ce44SJohn Forte 	case FC_IP_RING:
4445*fcf3ce44SJohn Forte 		HBASTATS.IpRcvEvent++;
4446*fcf3ce44SJohn Forte 		RcvError = &HBASTATS.IpDropped;
4447*fcf3ce44SJohn Forte 		RcvDropped = &HBASTATS.IpDropped;
4448*fcf3ce44SJohn Forte 		UbPosted = &HBASTATS.IpUbPosted;
4449*fcf3ce44SJohn Forte 		dropped_msg = &emlxs_unsol_ip_dropped_msg;
4450*fcf3ce44SJohn Forte 		buf_type = MEM_IPBUF;
4451*fcf3ce44SJohn Forte 		break;
4452*fcf3ce44SJohn Forte 
4453*fcf3ce44SJohn Forte 	case FC_ELS_RING:
4454*fcf3ce44SJohn Forte 		HBASTATS.ElsRcvEvent++;
4455*fcf3ce44SJohn Forte 		RcvError = &HBASTATS.ElsRcvError;
4456*fcf3ce44SJohn Forte 		RcvDropped = &HBASTATS.ElsRcvDropped;
4457*fcf3ce44SJohn Forte 		UbPosted = &HBASTATS.ElsUbPosted;
4458*fcf3ce44SJohn Forte 		dropped_msg = &emlxs_unsol_els_dropped_msg;
4459*fcf3ce44SJohn Forte 		buf_type = MEM_ELSBUF;
4460*fcf3ce44SJohn Forte 		break;
4461*fcf3ce44SJohn Forte 
4462*fcf3ce44SJohn Forte 	case FC_CT_RING:
4463*fcf3ce44SJohn Forte 		HBASTATS.CtRcvEvent++;
4464*fcf3ce44SJohn Forte 		RcvError = &HBASTATS.CtRcvError;
4465*fcf3ce44SJohn Forte 		RcvDropped = &HBASTATS.CtRcvDropped;
4466*fcf3ce44SJohn Forte 		UbPosted = &HBASTATS.CtUbPosted;
4467*fcf3ce44SJohn Forte 		dropped_msg = &emlxs_unsol_ct_dropped_msg;
4468*fcf3ce44SJohn Forte 		buf_type = MEM_CTBUF;
4469*fcf3ce44SJohn Forte 		break;
4470*fcf3ce44SJohn Forte 
4471*fcf3ce44SJohn Forte 	default:
4472*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
4473*fcf3ce44SJohn Forte 		    "ring=%d cmd=%x  %s %x %x %x %x",
4474*fcf3ce44SJohn Forte 		    ringno, iocb->ulpCommand,
4475*fcf3ce44SJohn Forte 		    emlxs_state_xlate(iocb->ulpStatus),
4476*fcf3ce44SJohn Forte 		    word[4], word[5], word[6], word[7]);
4477*fcf3ce44SJohn Forte 		return (1);
4478*fcf3ce44SJohn Forte 	}
4479*fcf3ce44SJohn Forte 
4480*fcf3ce44SJohn Forte 	if (iocb->ulpStatus) {
4481*fcf3ce44SJohn Forte 		if ((iocb->ulpStatus == IOSTAT_LOCAL_REJECT) &&
4482*fcf3ce44SJohn Forte 		    (iocb->un.grsp.perr.statLocalError ==
4483*fcf3ce44SJohn Forte 		    IOERR_RCV_BUFFER_TIMEOUT)) {
4484*fcf3ce44SJohn Forte 			(void) strcpy(error_str, "Out of posted buffers:");
4485*fcf3ce44SJohn Forte 		} else if ((iocb->ulpStatus == IOSTAT_LOCAL_REJECT) &&
4486*fcf3ce44SJohn Forte 		    (iocb->un.grsp.perr.statLocalError ==
4487*fcf3ce44SJohn Forte 		    IOERR_RCV_BUFFER_WAITING)) {
4488*fcf3ce44SJohn Forte 			(void) strcpy(error_str, "Buffer waiting:");
4489*fcf3ce44SJohn Forte 			goto done;
4490*fcf3ce44SJohn Forte 		} else if (iocb->ulpStatus == IOSTAT_ILLEGAL_FRAME_RCVD) {
4491*fcf3ce44SJohn Forte 			(void) strcpy(error_str, "Illegal frame:");
4492*fcf3ce44SJohn Forte 		} else {
4493*fcf3ce44SJohn Forte 			(void) strcpy(error_str, "General error:");
4494*fcf3ce44SJohn Forte 		}
4495*fcf3ce44SJohn Forte 
4496*fcf3ce44SJohn Forte 		goto failed;
4497*fcf3ce44SJohn Forte 	}
4498*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
4499*fcf3ce44SJohn Forte 	if (hba->flag & FC_HBQ_ENABLED) {
4500*fcf3ce44SJohn Forte 		HBQ_INIT_t *hbq;
4501*fcf3ce44SJohn Forte 		HBQE_t *hbqE;
4502*fcf3ce44SJohn Forte 		uint32_t hbqe_tag;
4503*fcf3ce44SJohn Forte 
4504*fcf3ce44SJohn Forte 		*UbPosted -= 1;
4505*fcf3ce44SJohn Forte 
4506*fcf3ce44SJohn Forte 		hbqE = (HBQE_t *)iocb;
4507*fcf3ce44SJohn Forte 		hbq_id = hbqE->unt.ext.HBQ_tag;
4508*fcf3ce44SJohn Forte 		hbqe_tag = hbqE->unt.ext.HBQE_tag;
4509*fcf3ce44SJohn Forte 
4510*fcf3ce44SJohn Forte 		hbq = &hba->hbq_table[hbq_id];
4511*fcf3ce44SJohn Forte 
4512*fcf3ce44SJohn Forte 		if (hbqe_tag >= hbq->HBQ_numEntries) {
4513*fcf3ce44SJohn Forte 			(void) sprintf(error_str, "Invalid HBQE tag=%x:",
4514*fcf3ce44SJohn Forte 			    hbqe_tag);
4515*fcf3ce44SJohn Forte 			goto dropped;
4516*fcf3ce44SJohn Forte 		}
4517*fcf3ce44SJohn Forte 		mp = hba->hbq_table[hbq_id].HBQ_PostBufs[hbqe_tag];
4518*fcf3ce44SJohn Forte 
4519*fcf3ce44SJohn Forte 		size = iocb->unsli3.ext_rcv.seq_len;
4520*fcf3ce44SJohn Forte 	} else
4521*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
4522*fcf3ce44SJohn Forte 	{
4523*fcf3ce44SJohn Forte 		bdeAddr = getPaddr(iocb->un.cont64[0].addrHigh,
4524*fcf3ce44SJohn Forte 		    iocb->un.cont64[0].addrLow);
4525*fcf3ce44SJohn Forte 
4526*fcf3ce44SJohn Forte 		/* Check for invalid buffer */
4527*fcf3ce44SJohn Forte 		if (iocb->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID) {
4528*fcf3ce44SJohn Forte 			(void) strcpy(error_str, "Invalid buffer:");
4529*fcf3ce44SJohn Forte 			goto dropped;
4530*fcf3ce44SJohn Forte 		}
4531*fcf3ce44SJohn Forte 		mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr);
4532*fcf3ce44SJohn Forte 
4533*fcf3ce44SJohn Forte 		size = iocb->un.rcvseq64.rcvBde.tus.f.bdeSize;
4534*fcf3ce44SJohn Forte 	}
4535*fcf3ce44SJohn Forte 
4536*fcf3ce44SJohn Forte 	if (!mp) {
4537*fcf3ce44SJohn Forte 		(void) strcpy(error_str, "Buffer not mapped:");
4538*fcf3ce44SJohn Forte 		goto dropped;
4539*fcf3ce44SJohn Forte 	}
4540*fcf3ce44SJohn Forte 	if (!size) {
4541*fcf3ce44SJohn Forte 		(void) strcpy(error_str, "Buffer empty:");
4542*fcf3ce44SJohn Forte 		goto dropped;
4543*fcf3ce44SJohn Forte 	}
4544*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
4545*fcf3ce44SJohn Forte 	/* To avoid we drop the broadcast packets */
4546*fcf3ce44SJohn Forte 	if (ringno != FC_IP_RING) {
4547*fcf3ce44SJohn Forte 		/* Get virtual port */
4548*fcf3ce44SJohn Forte 		if (hba->flag & FC_NPIV_ENABLED) {
4549*fcf3ce44SJohn Forte 			vpi = iocb->unsli3.ext_rcv.vpi;
4550*fcf3ce44SJohn Forte 			if (vpi >= hba->vpi_max) {
4551*fcf3ce44SJohn Forte 				(void) sprintf(error_str, "Invalid VPI=%d:",
4552*fcf3ce44SJohn Forte 				    vpi);
4553*fcf3ce44SJohn Forte 				goto dropped;
4554*fcf3ce44SJohn Forte 			}
4555*fcf3ce44SJohn Forte 			port = &VPORT(vpi);
4556*fcf3ce44SJohn Forte 		}
4557*fcf3ce44SJohn Forte 	}
4558*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
4559*fcf3ce44SJohn Forte 
4560*fcf3ce44SJohn Forte 	/* Process request */
4561*fcf3ce44SJohn Forte 	switch (ringno) {
4562*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
4563*fcf3ce44SJohn Forte 	case FC_FCT_RING:
4564*fcf3ce44SJohn Forte 		(void) emlxs_fct_handle_unsol_req(port, rp, iocbq, mp, size);
4565*fcf3ce44SJohn Forte 		break;
4566*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
4567*fcf3ce44SJohn Forte 
4568*fcf3ce44SJohn Forte 	case FC_IP_RING:
4569*fcf3ce44SJohn Forte 		(void) emlxs_ip_handle_unsol_req(port, rp, iocbq, mp, size);
4570*fcf3ce44SJohn Forte 		break;
4571*fcf3ce44SJohn Forte 
4572*fcf3ce44SJohn Forte 	case FC_ELS_RING:
4573*fcf3ce44SJohn Forte 		/* If this is a target port, then let fct handle this */
4574*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
4575*fcf3ce44SJohn Forte 		if (port->tgt_mode) {
4576*fcf3ce44SJohn Forte 			(void) emlxs_fct_handle_unsol_els(port, rp, iocbq,
4577*fcf3ce44SJohn Forte 			    mp, size);
4578*fcf3ce44SJohn Forte 		} else {
4579*fcf3ce44SJohn Forte 			(void) emlxs_els_handle_unsol_req(port, rp, iocbq,
4580*fcf3ce44SJohn Forte 			    mp, size);
4581*fcf3ce44SJohn Forte 		}
4582*fcf3ce44SJohn Forte #else
4583*fcf3ce44SJohn Forte 		(void) emlxs_els_handle_unsol_req(port, rp, iocbq,
4584*fcf3ce44SJohn Forte 		    mp, size);
4585*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
4586*fcf3ce44SJohn Forte 		break;
4587*fcf3ce44SJohn Forte 
4588*fcf3ce44SJohn Forte 	case FC_CT_RING:
4589*fcf3ce44SJohn Forte 		(void) emlxs_ct_handle_unsol_req(port, rp, iocbq, mp, size);
4590*fcf3ce44SJohn Forte 		break;
4591*fcf3ce44SJohn Forte 	}
4592*fcf3ce44SJohn Forte 
4593*fcf3ce44SJohn Forte 	goto done;
4594*fcf3ce44SJohn Forte 
4595*fcf3ce44SJohn Forte dropped:
4596*fcf3ce44SJohn Forte 	*RcvDropped += 1;
4597*fcf3ce44SJohn Forte 
4598*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, dropped_msg,
4599*fcf3ce44SJohn Forte 	    "%s: cmd=%x  %s %x %x %x %x",
4600*fcf3ce44SJohn Forte 	    error_str, iocb->ulpCommand, emlxs_state_xlate(iocb->ulpStatus),
4601*fcf3ce44SJohn Forte 	    word[4], word[5], word[6], word[7]);
4602*fcf3ce44SJohn Forte 
4603*fcf3ce44SJohn Forte 	if (ringno == FC_FCT_RING) {
4604*fcf3ce44SJohn Forte 		uint32_t sid;
4605*fcf3ce44SJohn Forte 
4606*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
4607*fcf3ce44SJohn Forte 		if (hba->sli_mode >= 3) {
4608*fcf3ce44SJohn Forte 			emlxs_node_t *ndlp;
4609*fcf3ce44SJohn Forte 			ndlp = emlxs_node_find_rpi(port, iocb->ulpIoTag);
4610*fcf3ce44SJohn Forte 			sid = ndlp->nlp_DID;
4611*fcf3ce44SJohn Forte 		} else
4612*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
4613*fcf3ce44SJohn Forte 		{
4614*fcf3ce44SJohn Forte 			sid = iocb->un.ulpWord[4] & 0xFFFFFF;
4615*fcf3ce44SJohn Forte 		}
4616*fcf3ce44SJohn Forte 
4617*fcf3ce44SJohn Forte 		emlxs_send_logo(port, sid);
4618*fcf3ce44SJohn Forte 	}
4619*fcf3ce44SJohn Forte 	goto done;
4620*fcf3ce44SJohn Forte 
4621*fcf3ce44SJohn Forte failed:
4622*fcf3ce44SJohn Forte 	*RcvError += 1;
4623*fcf3ce44SJohn Forte 
4624*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, dropped_msg,
4625*fcf3ce44SJohn Forte 	    "%s: cmd=%x %s  %x %x %x %x  hba:%x %x",
4626*fcf3ce44SJohn Forte 	    error_str, iocb->ulpCommand, emlxs_state_xlate(iocb->ulpStatus),
4627*fcf3ce44SJohn Forte 	    word[4], word[5], word[6], word[7], hba->state, hba->flag);
4628*fcf3ce44SJohn Forte 
4629*fcf3ce44SJohn Forte done:
4630*fcf3ce44SJohn Forte 
4631*fcf3ce44SJohn Forte #ifdef SLI3_SUPPORT
4632*fcf3ce44SJohn Forte 	if (hba->flag & FC_HBQ_ENABLED) {
4633*fcf3ce44SJohn Forte 		emlxs_update_HBQ_index(hba, hbq_id);
4634*fcf3ce44SJohn Forte 	} else
4635*fcf3ce44SJohn Forte #endif	/* SLI3_SUPPORT */
4636*fcf3ce44SJohn Forte 	{
4637*fcf3ce44SJohn Forte 		if (mp) {
4638*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, buf_type, (uint8_t *)mp);
4639*fcf3ce44SJohn Forte 		}
4640*fcf3ce44SJohn Forte 		(void) emlxs_post_buffer(hba, rp, 1);
4641*fcf3ce44SJohn Forte 	}
4642*fcf3ce44SJohn Forte 
4643*fcf3ce44SJohn Forte 	return (0);
4644*fcf3ce44SJohn Forte 
4645*fcf3ce44SJohn Forte } /* emlxs_handle_rcv_seq() */
4646*fcf3ce44SJohn Forte 
4647*fcf3ce44SJohn Forte 
4648*fcf3ce44SJohn Forte 
4649*fcf3ce44SJohn Forte extern void
4650*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
4651*fcf3ce44SJohn Forte {
4652*fcf3ce44SJohn Forte 	PGP *pgp;
4653*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
4654*fcf3ce44SJohn Forte 	SLIM2 *slim2p = (SLIM2 *)hba->slim2.virt;
4655*fcf3ce44SJohn Forte 	uint32_t nextIdx;
4656*fcf3ce44SJohn Forte 	uint32_t status;
4657*fcf3ce44SJohn Forte 	void *ioa2;
4658*fcf3ce44SJohn Forte 	off_t offset;
4659*fcf3ce44SJohn Forte 	uint32_t count;
4660*fcf3ce44SJohn Forte 	uint32_t ringno;
4661*fcf3ce44SJohn Forte 	int32_t throttle;
4662*fcf3ce44SJohn Forte 
4663*fcf3ce44SJohn Forte 	ringno = rp->ringno;
4664*fcf3ce44SJohn Forte 	throttle = 0;
4665*fcf3ce44SJohn Forte 
4666*fcf3ce44SJohn Forte begin:
4667*fcf3ce44SJohn Forte 
4668*fcf3ce44SJohn Forte 	/* Check if FCP ring and adapter is not ready */
4669*fcf3ce44SJohn Forte 	if ((ringno == FC_FCP_RING) && (hba->state != FC_READY)) {
4670*fcf3ce44SJohn Forte 		if (!iocbq) {
4671*fcf3ce44SJohn Forte 			return;
4672*fcf3ce44SJohn Forte 		}
4673*fcf3ce44SJohn Forte 		if (!(iocbq->flag & IOCB_SPECIAL) || !iocbq->port ||
4674*fcf3ce44SJohn Forte 		    !(((emlxs_port_t *)iocbq->port)->tgt_mode)) {
4675*fcf3ce44SJohn Forte 			emlxs_tx_put(iocbq, 1);
4676*fcf3ce44SJohn Forte 			return;
4677*fcf3ce44SJohn Forte 		}
4678*fcf3ce44SJohn Forte 	}
4679*fcf3ce44SJohn Forte 	/* Attempt to acquire CMD_RING lock */
4680*fcf3ce44SJohn Forte 	if (mutex_tryenter(&EMLXS_CMD_RING_LOCK(ringno)) == 0) {
4681*fcf3ce44SJohn Forte 		/* Queue it for later */
4682*fcf3ce44SJohn Forte 		if (iocbq) {
4683*fcf3ce44SJohn Forte 			if ((hba->io_count[ringno] -
4684*fcf3ce44SJohn Forte 			    hba->ring_tx_count[ringno]) > 10) {
4685*fcf3ce44SJohn Forte 				emlxs_tx_put(iocbq, 1);
4686*fcf3ce44SJohn Forte 				return;
4687*fcf3ce44SJohn Forte 			} else {
4688*fcf3ce44SJohn Forte 
4689*fcf3ce44SJohn Forte 				/*
4690*fcf3ce44SJohn Forte 				 * EMLXS_MSGF(EMLXS_CONTEXT,
4691*fcf3ce44SJohn Forte 				 * &emlxs_ring_watchdog_msg, "%s host=%d
4692*fcf3ce44SJohn Forte 				 * port=%d cnt=%d,%d  RACE CONDITION3
4693*fcf3ce44SJohn Forte 				 * DETECTED.", emlxs_ring_xlate(ringno),
4694*fcf3ce44SJohn Forte 				 * rp->fc_cmdidx, rp->fc_port_cmdidx,
4695*fcf3ce44SJohn Forte 				 * hba->ring_tx_count[ringno],
4696*fcf3ce44SJohn Forte 				 * hba->io_count[ringno]);
4697*fcf3ce44SJohn Forte 				 */
4698*fcf3ce44SJohn Forte 				mutex_enter(&EMLXS_CMD_RING_LOCK(ringno));
4699*fcf3ce44SJohn Forte 			}
4700*fcf3ce44SJohn Forte 		} else {
4701*fcf3ce44SJohn Forte 			return;
4702*fcf3ce44SJohn Forte 		}
4703*fcf3ce44SJohn Forte 	}
4704*fcf3ce44SJohn Forte 	/* CMD_RING_LOCK acquired */
4705*fcf3ce44SJohn Forte 
4706*fcf3ce44SJohn Forte 	/* Check if HBA is full */
4707*fcf3ce44SJohn Forte 	throttle = hba->io_throttle - hba->io_active;
4708*fcf3ce44SJohn Forte 	if (throttle <= 0) {
4709*fcf3ce44SJohn Forte 		/* Hitting adapter throttle limit */
4710*fcf3ce44SJohn Forte 		/* Queue it for later */
4711*fcf3ce44SJohn Forte 		if (iocbq) {
4712*fcf3ce44SJohn Forte 			emlxs_tx_put(iocbq, 1);
4713*fcf3ce44SJohn Forte 		}
4714*fcf3ce44SJohn Forte 		goto busy;
4715*fcf3ce44SJohn Forte 	}
4716*fcf3ce44SJohn Forte 	/* Read adapter's get index */
4717*fcf3ce44SJohn Forte 	pgp = (PGP *) & ((SLIM2 *) hba->slim2.virt)->mbx.us.s2.port[ringno];
4718*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)&(pgp->cmdGetInx) -
4719*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
4720*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4721*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
4722*fcf3ce44SJohn Forte 	rp->fc_port_cmdidx = PCIMEM_LONG(pgp->cmdGetInx);
4723*fcf3ce44SJohn Forte 
4724*fcf3ce44SJohn Forte 	/* Calculate the next put index */
4725*fcf3ce44SJohn Forte 	nextIdx = (rp->fc_cmdidx + 1 >= rp->fc_numCiocb) ?
4726*fcf3ce44SJohn Forte 	    0 : rp->fc_cmdidx + 1;
4727*fcf3ce44SJohn Forte 
4728*fcf3ce44SJohn Forte 	/* Check if ring is full */
4729*fcf3ce44SJohn Forte 	if (nextIdx == rp->fc_port_cmdidx) {
4730*fcf3ce44SJohn Forte 		/* Try one more time */
4731*fcf3ce44SJohn Forte 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4732*fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
4733*fcf3ce44SJohn Forte 		rp->fc_port_cmdidx = PCIMEM_LONG(pgp->cmdGetInx);
4734*fcf3ce44SJohn Forte 
4735*fcf3ce44SJohn Forte 		if (nextIdx == rp->fc_port_cmdidx) {
4736*fcf3ce44SJohn Forte 			/* Queue it for later */
4737*fcf3ce44SJohn Forte 			if (iocbq) {
4738*fcf3ce44SJohn Forte 				emlxs_tx_put(iocbq, 1);
4739*fcf3ce44SJohn Forte 			}
4740*fcf3ce44SJohn Forte 			goto busy;
4741*fcf3ce44SJohn Forte 		}
4742*fcf3ce44SJohn Forte 	}
4743*fcf3ce44SJohn Forte 	/* We have a command ring slot available */
4744*fcf3ce44SJohn Forte 	/* Make sure we have an iocb to send */
4745*fcf3ce44SJohn Forte 
4746*fcf3ce44SJohn Forte 	if (iocbq) {
4747*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_RINGTX_LOCK);
4748*fcf3ce44SJohn Forte 
4749*fcf3ce44SJohn Forte 		/* Check if the ring already has iocb's waiting */
4750*fcf3ce44SJohn Forte 		if (rp->nodeq.q_first != NULL) {
4751*fcf3ce44SJohn Forte 			/* Put the current iocbq on the tx queue */
4752*fcf3ce44SJohn Forte 			emlxs_tx_put(iocbq, 0);
4753*fcf3ce44SJohn Forte 
4754*fcf3ce44SJohn Forte 			/*
4755*fcf3ce44SJohn Forte 			 * Attempt to replace it with the next iocbq in the
4756*fcf3ce44SJohn Forte 			 * tx queue
4757*fcf3ce44SJohn Forte 			 */
4758*fcf3ce44SJohn Forte 			iocbq = emlxs_tx_get(rp, 0);
4759*fcf3ce44SJohn Forte 		}
4760*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_RINGTX_LOCK);
4761*fcf3ce44SJohn Forte 	} else {
4762*fcf3ce44SJohn Forte 		/* Try to get the next iocb on the tx queue */
4763*fcf3ce44SJohn Forte 		iocbq = emlxs_tx_get(rp, 1);
4764*fcf3ce44SJohn Forte 	}
4765*fcf3ce44SJohn Forte 
4766*fcf3ce44SJohn Forte sendit:
4767*fcf3ce44SJohn Forte 	count = 0;
4768*fcf3ce44SJohn Forte 
4769*fcf3ce44SJohn Forte 	/* Process each iocbq */
4770*fcf3ce44SJohn Forte 	while (iocbq) {
4771*fcf3ce44SJohn Forte 
4772*fcf3ce44SJohn Forte #ifdef NPIV_SUPPORT
4773*fcf3ce44SJohn Forte 		sbp = iocbq->sbp;
4774*fcf3ce44SJohn Forte 		if (sbp && (sbp->pkt_flags & PACKET_DELAY_REQUIRED)) {
4775*fcf3ce44SJohn Forte 			/*
4776*fcf3ce44SJohn Forte 			 * Update adapter if needed, since we are about to
4777*fcf3ce44SJohn Forte 			 * delay here
4778*fcf3ce44SJohn Forte 			 */
4779*fcf3ce44SJohn Forte 			if (count) {
4780*fcf3ce44SJohn Forte 				count = 0;
4781*fcf3ce44SJohn Forte 
4782*fcf3ce44SJohn Forte 				/* Update the adapter's cmd put index */
4783*fcf3ce44SJohn Forte 				if (hba->bus_type == SBUS_FC) {
4784*fcf3ce44SJohn Forte 					slim2p->mbx.us.s2.host[ringno].
4785*fcf3ce44SJohn Forte 					    cmdPutInx =
4786*fcf3ce44SJohn Forte 					    PCIMEM_LONG(rp->fc_cmdidx);
4787*fcf3ce44SJohn Forte 
4788*fcf3ce44SJohn Forte 					/* DMA sync the index for the adapter */
4789*fcf3ce44SJohn Forte 					offset =
4790*fcf3ce44SJohn Forte 					    (off_t)
4791*fcf3ce44SJohn Forte 					    ((uint64_t)(unsigned long)&(slim2p->
4792*fcf3ce44SJohn Forte 					    mbx.us.s2.host[ringno].cmdPutInx) -
4793*fcf3ce44SJohn Forte 					    (uint64_t)(unsigned long)slim2p);
4794*fcf3ce44SJohn Forte 					emlxs_mpdata_sync(hba->slim2.dma_handle,
4795*fcf3ce44SJohn Forte 					    offset, 4, DDI_DMA_SYNC_FORDEV);
4796*fcf3ce44SJohn Forte 				} else {
4797*fcf3ce44SJohn Forte 					ioa2 = (void *)((char *)hba->slim_addr +
4798*fcf3ce44SJohn Forte 					    hba->hgp_ring_offset +
4799*fcf3ce44SJohn Forte 					    ((ringno * 2) * sizeof (uint32_t)));
4800*fcf3ce44SJohn Forte 					WRITE_SLIM_ADDR(hba,
4801*fcf3ce44SJohn Forte 					    (volatile uint32_t *)ioa2,
4802*fcf3ce44SJohn Forte 					    rp->fc_cmdidx);
4803*fcf3ce44SJohn Forte 				}
4804*fcf3ce44SJohn Forte 
4805*fcf3ce44SJohn Forte 				status = (CA_R0ATT << (ringno * 4));
4806*fcf3ce44SJohn Forte 				WRITE_CSR_REG(hba,
4807*fcf3ce44SJohn Forte 				    FC_CA_REG(hba, hba->csr_addr),
4808*fcf3ce44SJohn Forte 				    (volatile uint32_t)status);
4809*fcf3ce44SJohn Forte 
4810*fcf3ce44SJohn Forte 			}
4811*fcf3ce44SJohn Forte 			/* Perform delay */
4812*fcf3ce44SJohn Forte 			if (ringno == FC_ELS_RING) {
4813*fcf3ce44SJohn Forte 				(void) drv_usecwait(100000);
4814*fcf3ce44SJohn Forte 			} else {
4815*fcf3ce44SJohn Forte 				(void) drv_usecwait(20000);
4816*fcf3ce44SJohn Forte 			}
4817*fcf3ce44SJohn Forte 		}
4818*fcf3ce44SJohn Forte #endif	/* NPIV_SUPPORT */
4819*fcf3ce44SJohn Forte 
4820*fcf3ce44SJohn Forte 		/* At this point, we have a command ring slot available */
4821*fcf3ce44SJohn Forte 		/* and an iocb to send */
4822*fcf3ce44SJohn Forte 
4823*fcf3ce44SJohn Forte 		/* Send the iocb */
4824*fcf3ce44SJohn Forte 		emlxs_issue_iocb(hba, rp, iocbq);
4825*fcf3ce44SJohn Forte 
4826*fcf3ce44SJohn Forte 		count++;
4827*fcf3ce44SJohn Forte 
4828*fcf3ce44SJohn Forte 		/* Check if HBA is full */
4829*fcf3ce44SJohn Forte 		throttle = hba->io_throttle - hba->io_active;
4830*fcf3ce44SJohn Forte 		if (throttle <= 0) {
4831*fcf3ce44SJohn Forte 			goto busy;
4832*fcf3ce44SJohn Forte 		}
4833*fcf3ce44SJohn Forte 		/* Calculate the next put index */
4834*fcf3ce44SJohn Forte 		nextIdx = (rp->fc_cmdidx + 1 >= rp->fc_numCiocb) ?
4835*fcf3ce44SJohn Forte 		    0 : rp->fc_cmdidx + 1;
4836*fcf3ce44SJohn Forte 
4837*fcf3ce44SJohn Forte 		/* Check if ring is full */
4838*fcf3ce44SJohn Forte 		if (nextIdx == rp->fc_port_cmdidx) {
4839*fcf3ce44SJohn Forte 			/* Try one more time */
4840*fcf3ce44SJohn Forte 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4841*fcf3ce44SJohn Forte 			    DDI_DMA_SYNC_FORKERNEL);
4842*fcf3ce44SJohn Forte 			rp->fc_port_cmdidx = PCIMEM_LONG(pgp->cmdGetInx);
4843*fcf3ce44SJohn Forte 
4844*fcf3ce44SJohn Forte 			if (nextIdx == rp->fc_port_cmdidx) {
4845*fcf3ce44SJohn Forte 				goto busy;
4846*fcf3ce44SJohn Forte 			}
4847*fcf3ce44SJohn Forte 		}
4848*fcf3ce44SJohn Forte 		/* Get the next iocb from the tx queue if there is one */
4849*fcf3ce44SJohn Forte 		iocbq = emlxs_tx_get(rp, 1);
4850*fcf3ce44SJohn Forte 	}
4851*fcf3ce44SJohn Forte 
4852*fcf3ce44SJohn Forte 	if (count) {
4853*fcf3ce44SJohn Forte 		/* Update the adapter's cmd put index */
4854*fcf3ce44SJohn Forte 		if (hba->bus_type == SBUS_FC) {
4855*fcf3ce44SJohn Forte 			slim2p->mbx.us.s2.host[ringno].
4856*fcf3ce44SJohn Forte 			    cmdPutInx = PCIMEM_LONG(rp->fc_cmdidx);
4857*fcf3ce44SJohn Forte 
4858*fcf3ce44SJohn Forte 			/* DMA sync the index for the adapter */
4859*fcf3ce44SJohn Forte 			offset = (off_t)
4860*fcf3ce44SJohn Forte 			    ((uint64_t)(unsigned long)&(slim2p->mbx.us.s2.
4861*fcf3ce44SJohn Forte 			    host[ringno].cmdPutInx) -
4862*fcf3ce44SJohn Forte 			    (uint64_t)(unsigned long)slim2p);
4863*fcf3ce44SJohn Forte 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4864*fcf3ce44SJohn Forte 			    DDI_DMA_SYNC_FORDEV);
4865*fcf3ce44SJohn Forte 		} else {
4866*fcf3ce44SJohn Forte 			ioa2 = (void *) ((char *)hba->slim_addr +
4867*fcf3ce44SJohn Forte 			    hba->hgp_ring_offset + ((ringno * 2) *
4868*fcf3ce44SJohn Forte 			    sizeof (uint32_t)));
4869*fcf3ce44SJohn Forte 			WRITE_SLIM_ADDR(hba,
4870*fcf3ce44SJohn Forte 			    (volatile uint32_t *)ioa2, rp->fc_cmdidx);
4871*fcf3ce44SJohn Forte 		}
4872*fcf3ce44SJohn Forte 
4873*fcf3ce44SJohn Forte 		status = (CA_R0ATT << (ringno * 4));
4874*fcf3ce44SJohn Forte 		WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr),
4875*fcf3ce44SJohn Forte 		    (volatile uint32_t)status);
4876*fcf3ce44SJohn Forte 
4877*fcf3ce44SJohn Forte 		/* Check tx queue one more time before releasing */
4878*fcf3ce44SJohn Forte 		if ((iocbq = emlxs_tx_get(rp, 1))) {
4879*fcf3ce44SJohn Forte 			/*
4880*fcf3ce44SJohn Forte 			 * EMLXS_MSGF(EMLXS_CONTEXT,
4881*fcf3ce44SJohn Forte 			 * &emlxs_ring_watchdog_msg, "%s host=%d port=%d
4882*fcf3ce44SJohn Forte 			 * RACE CONDITION1 DETECTED.",
4883*fcf3ce44SJohn Forte 			 * emlxs_ring_xlate(ringno), rp->fc_cmdidx,
4884*fcf3ce44SJohn Forte 			 * rp->fc_port_cmdidx);
4885*fcf3ce44SJohn Forte 			 */
4886*fcf3ce44SJohn Forte 			goto sendit;
4887*fcf3ce44SJohn Forte 		}
4888*fcf3ce44SJohn Forte 	}
4889*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_CMD_RING_LOCK(ringno));
4890*fcf3ce44SJohn Forte 
4891*fcf3ce44SJohn Forte 	return;
4892*fcf3ce44SJohn Forte 
4893*fcf3ce44SJohn Forte busy:
4894*fcf3ce44SJohn Forte 
4895*fcf3ce44SJohn Forte 	/*
4896*fcf3ce44SJohn Forte 	 * Set ring to SET R0CE_REQ in Chip Att register. Chip will tell us
4897*fcf3ce44SJohn Forte 	 * when an entry is freed.
4898*fcf3ce44SJohn Forte 	 */
4899*fcf3ce44SJohn Forte 	if (count) {
4900*fcf3ce44SJohn Forte 		/* Update the adapter's cmd put index */
4901*fcf3ce44SJohn Forte 		if (hba->bus_type == SBUS_FC) {
4902*fcf3ce44SJohn Forte 			slim2p->mbx.us.s2.host[ringno].cmdPutInx =
4903*fcf3ce44SJohn Forte 			    PCIMEM_LONG(rp->fc_cmdidx);
4904*fcf3ce44SJohn Forte 
4905*fcf3ce44SJohn Forte 			/* DMA sync the index for the adapter */
4906*fcf3ce44SJohn Forte 			offset = (off_t)
4907*fcf3ce44SJohn Forte 			    ((uint64_t)(unsigned long)&(slim2p->mbx.us.s2.
4908*fcf3ce44SJohn Forte 			    host[ringno].cmdPutInx) -
4909*fcf3ce44SJohn Forte 			    (uint64_t)(unsigned long)slim2p);
4910*fcf3ce44SJohn Forte 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
4911*fcf3ce44SJohn Forte 			    DDI_DMA_SYNC_FORDEV);
4912*fcf3ce44SJohn Forte 		} else {
4913*fcf3ce44SJohn Forte 			ioa2 = (void *) ((char *)hba->slim_addr +
4914*fcf3ce44SJohn Forte 			    hba->hgp_ring_offset + ((ringno * 2) *
4915*fcf3ce44SJohn Forte 			    sizeof (uint32_t)));
4916*fcf3ce44SJohn Forte 			WRITE_SLIM_ADDR(hba, (volatile uint32_t *) ioa2,
4917*fcf3ce44SJohn Forte 			    rp->fc_cmdidx);
4918*fcf3ce44SJohn Forte 		}
4919*fcf3ce44SJohn Forte 	}
4920*fcf3ce44SJohn Forte 	status = ((CA_R0ATT | CA_R0CE_REQ) << (ringno * 4));
4921*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr),
4922*fcf3ce44SJohn Forte 	    (volatile uint32_t) status);
4923*fcf3ce44SJohn Forte 
4924*fcf3ce44SJohn Forte 	if (throttle <= 0) {
4925*fcf3ce44SJohn Forte 		HBASTATS.IocbThrottled++;
4926*fcf3ce44SJohn Forte 	} else {
4927*fcf3ce44SJohn Forte 		HBASTATS.IocbRingFull[ringno]++;
4928*fcf3ce44SJohn Forte 	}
4929*fcf3ce44SJohn Forte 
4930*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_CMD_RING_LOCK(ringno));
4931*fcf3ce44SJohn Forte 
4932*fcf3ce44SJohn Forte 	return;
4933*fcf3ce44SJohn Forte 
4934*fcf3ce44SJohn Forte } /* emlxs_issue_iocb_cmd() */
4935*fcf3ce44SJohn Forte 
4936*fcf3ce44SJohn Forte 
4937*fcf3ce44SJohn Forte 
4938*fcf3ce44SJohn Forte /* EMLXS_CMD_RING_LOCK must be held when calling this function */
4939*fcf3ce44SJohn Forte static void
4940*fcf3ce44SJohn Forte emlxs_issue_iocb(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
4941*fcf3ce44SJohn Forte {
4942*fcf3ce44SJohn Forte 	emlxs_port_t *port;
4943*fcf3ce44SJohn Forte 	IOCB *icmd;
4944*fcf3ce44SJohn Forte 	IOCB *iocb;
4945*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
4946*fcf3ce44SJohn Forte 	off_t offset;
4947*fcf3ce44SJohn Forte 	uint32_t ringno;
4948*fcf3ce44SJohn Forte 
4949*fcf3ce44SJohn Forte 	ringno = rp->ringno;
4950*fcf3ce44SJohn Forte 	sbp = iocbq->sbp;
4951*fcf3ce44SJohn Forte 	icmd = &iocbq->iocb;
4952*fcf3ce44SJohn Forte 	port = iocbq->port;
4953*fcf3ce44SJohn Forte 
4954*fcf3ce44SJohn Forte 	HBASTATS.IocbIssued[ringno]++;
4955*fcf3ce44SJohn Forte 
4956*fcf3ce44SJohn Forte 	/* Check for ULP pkt request */
4957*fcf3ce44SJohn Forte 	if (sbp) {
4958*fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
4959*fcf3ce44SJohn Forte 
4960*fcf3ce44SJohn Forte 		if (sbp->node == NULL) {
4961*fcf3ce44SJohn Forte 			/* Set node to base node by default */
4962*fcf3ce44SJohn Forte 			iocbq->node = (void *) &port->node_base;
4963*fcf3ce44SJohn Forte 			sbp->node = (void *) &port->node_base;
4964*fcf3ce44SJohn Forte 		}
4965*fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_CHIPQ;
4966*fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
4967*fcf3ce44SJohn Forte 
4968*fcf3ce44SJohn Forte 		atomic_add_32(&hba->io_active, 1);
4969*fcf3ce44SJohn Forte 	}
4970*fcf3ce44SJohn Forte 	/* get the next available command ring iocb */
4971*fcf3ce44SJohn Forte 	iocb = (IOCB *) (((char *)rp->fc_cmdringaddr +
4972*fcf3ce44SJohn Forte 	    (rp->fc_cmdidx * hba->iocb_cmd_size)));
4973*fcf3ce44SJohn Forte 
4974*fcf3ce44SJohn Forte 	/* Copy the local iocb to the command ring iocb */
4975*fcf3ce44SJohn Forte 	emlxs_pcimem_bcopy((uint32_t *)icmd, (uint32_t *)iocb,
4976*fcf3ce44SJohn Forte 	    hba->iocb_cmd_size);
4977*fcf3ce44SJohn Forte 
4978*fcf3ce44SJohn Forte 	/* DMA sync the command ring iocb for the adapter */
4979*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)iocb -
4980*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
4981*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
4982*fcf3ce44SJohn Forte 	    hba->iocb_cmd_size, DDI_DMA_SYNC_FORDEV);
4983*fcf3ce44SJohn Forte 
4984*fcf3ce44SJohn Forte 	/* Free the local iocb if there is no sbp tracking it */
4985*fcf3ce44SJohn Forte 	if (!sbp) {
4986*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_IOCB, (uint8_t *)iocbq);
4987*fcf3ce44SJohn Forte 	}
4988*fcf3ce44SJohn Forte 	/* update local ring index to next available ring index */
4989*fcf3ce44SJohn Forte 	rp->fc_cmdidx = (rp->fc_cmdidx + 1 >= rp->fc_numCiocb) ?
4990*fcf3ce44SJohn Forte 	    0 : rp->fc_cmdidx + 1;
4991*fcf3ce44SJohn Forte 
4992*fcf3ce44SJohn Forte 
4993*fcf3ce44SJohn Forte 	return;
4994*fcf3ce44SJohn Forte 
4995*fcf3ce44SJohn Forte } /* emlxs_issue_iocb() */
4996*fcf3ce44SJohn Forte 
4997*fcf3ce44SJohn Forte 
4998*fcf3ce44SJohn Forte extern uint32_t
4999*fcf3ce44SJohn Forte emlxs_interlock(emlxs_hba_t *hba)
5000*fcf3ce44SJohn Forte {
5001*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5002*fcf3ce44SJohn Forte 	MAILBOX *swpmb;
5003*fcf3ce44SJohn Forte 	MAILBOX *mb2;
5004*fcf3ce44SJohn Forte 	MAILBOX *mb1;
5005*fcf3ce44SJohn Forte 	uint32_t word0;
5006*fcf3ce44SJohn Forte 	uint32_t j;
5007*fcf3ce44SJohn Forte 	uint32_t interlock_failed;
5008*fcf3ce44SJohn Forte 	uint32_t ha_copy;
5009*fcf3ce44SJohn Forte 	uint32_t value;
5010*fcf3ce44SJohn Forte 	off_t offset;
5011*fcf3ce44SJohn Forte 	uint32_t size;
5012*fcf3ce44SJohn Forte 
5013*fcf3ce44SJohn Forte 	interlock_failed = 0;
5014*fcf3ce44SJohn Forte 
5015*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
5016*fcf3ce44SJohn Forte 	if (hba->flag & FC_INTERLOCKED) {
5017*fcf3ce44SJohn Forte 		emlxs_ffstate_change_locked(hba, FC_KILLED);
5018*fcf3ce44SJohn Forte 
5019*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
5020*fcf3ce44SJohn Forte 
5021*fcf3ce44SJohn Forte 		return (FC_SUCCESS);
5022*fcf3ce44SJohn Forte 	}
5023*fcf3ce44SJohn Forte 	j = 0;
5024*fcf3ce44SJohn Forte 	while (j++ < 10000) {
5025*fcf3ce44SJohn Forte 		if (hba->mbox_queue_flag == 0) {
5026*fcf3ce44SJohn Forte 			break;
5027*fcf3ce44SJohn Forte 		}
5028*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
5029*fcf3ce44SJohn Forte 		DELAYUS(100);
5030*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
5031*fcf3ce44SJohn Forte 	}
5032*fcf3ce44SJohn Forte 
5033*fcf3ce44SJohn Forte 	if (hba->mbox_queue_flag != 0) {
5034*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5035*fcf3ce44SJohn Forte 		    "Interlock failed. Mailbox busy.");
5036*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
5037*fcf3ce44SJohn Forte 		return (FC_SUCCESS);
5038*fcf3ce44SJohn Forte 	}
5039*fcf3ce44SJohn Forte 	hba->flag |= FC_INTERLOCKED;
5040*fcf3ce44SJohn Forte 	hba->mbox_queue_flag = 1;
5041*fcf3ce44SJohn Forte 
5042*fcf3ce44SJohn Forte 	/* Disable all host interrupts */
5043*fcf3ce44SJohn Forte 	hba->hc_copy = 0;
5044*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
5045*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr), 0xffffffff);
5046*fcf3ce44SJohn Forte 
5047*fcf3ce44SJohn Forte 	mb2 = FC_SLIM2_MAILBOX(hba);
5048*fcf3ce44SJohn Forte 	mb1 = FC_SLIM1_MAILBOX(hba);
5049*fcf3ce44SJohn Forte 	swpmb = (MAILBOX *) & word0;
5050*fcf3ce44SJohn Forte 
5051*fcf3ce44SJohn Forte 	if (!(hba->flag & FC_SLIM2_MODE)) {
5052*fcf3ce44SJohn Forte 		goto mode_B;
5053*fcf3ce44SJohn Forte 	}
5054*fcf3ce44SJohn Forte mode_A:
5055*fcf3ce44SJohn Forte 
5056*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5057*fcf3ce44SJohn Forte 	    "Attempting SLIM2 Interlock...");
5058*fcf3ce44SJohn Forte 
5059*fcf3ce44SJohn Forte interlock_A:
5060*fcf3ce44SJohn Forte 
5061*fcf3ce44SJohn Forte 	value = 0xFFFFFFFF;
5062*fcf3ce44SJohn Forte 	word0 = 0;
5063*fcf3ce44SJohn Forte 	swpmb->mbxCommand = MBX_KILL_BOARD;
5064*fcf3ce44SJohn Forte 	swpmb->mbxOwner = OWN_CHIP;
5065*fcf3ce44SJohn Forte 
5066*fcf3ce44SJohn Forte 	/* Write value to SLIM */
5067*fcf3ce44SJohn Forte 	WRITE_SLIM_ADDR(hba, (((volatile uint32_t *) mb1) + 1), value);
5068*fcf3ce44SJohn Forte 	WRITE_SLIM_ADDR(hba, (((volatile uint32_t *) mb1)), word0);
5069*fcf3ce44SJohn Forte 
5070*fcf3ce44SJohn Forte 	/* Send Kill board request */
5071*fcf3ce44SJohn Forte 	mb2->un.varWords[0] = value;
5072*fcf3ce44SJohn Forte 	mb2->mbxCommand = MBX_KILL_BOARD;
5073*fcf3ce44SJohn Forte 	mb2->mbxOwner = OWN_CHIP;
5074*fcf3ce44SJohn Forte 
5075*fcf3ce44SJohn Forte 	/* Sync the memory */
5076*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)mb2 -
5077*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
5078*fcf3ce44SJohn Forte 	size = (sizeof (uint32_t) * 2);
5079*fcf3ce44SJohn Forte 	emlxs_pcimem_bcopy((uint32_t *)mb2, (uint32_t *)mb2, size);
5080*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset, size,
5081*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORDEV);
5082*fcf3ce44SJohn Forte 
5083*fcf3ce44SJohn Forte 	/* interrupt board to do it right away */
5084*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr), CA_MBATT);
5085*fcf3ce44SJohn Forte 
5086*fcf3ce44SJohn Forte 	/* First wait for command acceptence */
5087*fcf3ce44SJohn Forte 	j = 0;
5088*fcf3ce44SJohn Forte 	while (j++ < 1000) {
5089*fcf3ce44SJohn Forte 		value = READ_SLIM_ADDR(hba, (((volatile uint32_t *) mb1) + 1));
5090*fcf3ce44SJohn Forte 
5091*fcf3ce44SJohn Forte 		if (value == 0) {
5092*fcf3ce44SJohn Forte 			break;
5093*fcf3ce44SJohn Forte 		}
5094*fcf3ce44SJohn Forte 		DELAYUS(50);
5095*fcf3ce44SJohn Forte 	}
5096*fcf3ce44SJohn Forte 
5097*fcf3ce44SJohn Forte 	if (value == 0) {
5098*fcf3ce44SJohn Forte 		/* Now wait for mailbox ownership to clear */
5099*fcf3ce44SJohn Forte 		while (j++ < 10000) {
5100*fcf3ce44SJohn Forte 			word0 = READ_SLIM_ADDR(hba,
5101*fcf3ce44SJohn Forte 			    ((volatile uint32_t *)mb1));
5102*fcf3ce44SJohn Forte 
5103*fcf3ce44SJohn Forte 			if (swpmb->mbxOwner == 0) {
5104*fcf3ce44SJohn Forte 				break;
5105*fcf3ce44SJohn Forte 			}
5106*fcf3ce44SJohn Forte 			DELAYUS(50);
5107*fcf3ce44SJohn Forte 		}
5108*fcf3ce44SJohn Forte 
5109*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5110*fcf3ce44SJohn Forte 		    "Interlock succeeded.");
5111*fcf3ce44SJohn Forte 
5112*fcf3ce44SJohn Forte 		goto done;
5113*fcf3ce44SJohn Forte 	}
5114*fcf3ce44SJohn Forte 	/* Interlock failed !!! */
5115*fcf3ce44SJohn Forte 	interlock_failed = 1;
5116*fcf3ce44SJohn Forte 
5117*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5118*fcf3ce44SJohn Forte 	    "Interlock failed.");
5119*fcf3ce44SJohn Forte 
5120*fcf3ce44SJohn Forte mode_B:
5121*fcf3ce44SJohn Forte 
5122*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5123*fcf3ce44SJohn Forte 	    "Attempting SLIM1 Interlock...");
5124*fcf3ce44SJohn Forte 
5125*fcf3ce44SJohn Forte interlock_B:
5126*fcf3ce44SJohn Forte 
5127*fcf3ce44SJohn Forte 	value = 0xFFFFFFFF;
5128*fcf3ce44SJohn Forte 	word0 = 0;
5129*fcf3ce44SJohn Forte 	swpmb->mbxCommand = MBX_KILL_BOARD;
5130*fcf3ce44SJohn Forte 	swpmb->mbxOwner = OWN_CHIP;
5131*fcf3ce44SJohn Forte 
5132*fcf3ce44SJohn Forte 	/* Write KILL BOARD to mailbox */
5133*fcf3ce44SJohn Forte 	WRITE_SLIM_ADDR(hba, (((volatile uint32_t *) mb1) + 1), value);
5134*fcf3ce44SJohn Forte 	WRITE_SLIM_ADDR(hba, ((volatile uint32_t *) mb1), word0);
5135*fcf3ce44SJohn Forte 
5136*fcf3ce44SJohn Forte 	/* interrupt board to do it right away */
5137*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr), CA_MBATT);
5138*fcf3ce44SJohn Forte 
5139*fcf3ce44SJohn Forte 	/* First wait for command acceptence */
5140*fcf3ce44SJohn Forte 	j = 0;
5141*fcf3ce44SJohn Forte 	while (j++ < 1000) {
5142*fcf3ce44SJohn Forte 		value = READ_SLIM_ADDR(hba, (((volatile uint32_t *) mb1) + 1));
5143*fcf3ce44SJohn Forte 
5144*fcf3ce44SJohn Forte 		if (value == 0) {
5145*fcf3ce44SJohn Forte 			break;
5146*fcf3ce44SJohn Forte 		}
5147*fcf3ce44SJohn Forte 		DELAYUS(50);
5148*fcf3ce44SJohn Forte 	}
5149*fcf3ce44SJohn Forte 
5150*fcf3ce44SJohn Forte 	if (value == 0) {
5151*fcf3ce44SJohn Forte 		/* Now wait for mailbox ownership to clear */
5152*fcf3ce44SJohn Forte 		while (j++ < 10000) {
5153*fcf3ce44SJohn Forte 			word0 = READ_SLIM_ADDR(hba,
5154*fcf3ce44SJohn Forte 			    ((volatile uint32_t *)mb1));
5155*fcf3ce44SJohn Forte 
5156*fcf3ce44SJohn Forte 			if (swpmb->mbxOwner == 0) {
5157*fcf3ce44SJohn Forte 				break;
5158*fcf3ce44SJohn Forte 			}
5159*fcf3ce44SJohn Forte 			DELAYUS(50);
5160*fcf3ce44SJohn Forte 		}
5161*fcf3ce44SJohn Forte 
5162*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5163*fcf3ce44SJohn Forte 		    "Interlock succeeded.");
5164*fcf3ce44SJohn Forte 
5165*fcf3ce44SJohn Forte 		goto done;
5166*fcf3ce44SJohn Forte 	}
5167*fcf3ce44SJohn Forte 	/* Interlock failed !!! */
5168*fcf3ce44SJohn Forte 
5169*fcf3ce44SJohn Forte 	/* If this is the first time then try again */
5170*fcf3ce44SJohn Forte 	if (interlock_failed == 0) {
5171*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5172*fcf3ce44SJohn Forte 		    "Interlock failed. Retrying...");
5173*fcf3ce44SJohn Forte 
5174*fcf3ce44SJohn Forte 		/* Try again */
5175*fcf3ce44SJohn Forte 		interlock_failed = 1;
5176*fcf3ce44SJohn Forte 		goto interlock_B;
5177*fcf3ce44SJohn Forte 	}
5178*fcf3ce44SJohn Forte 	/*
5179*fcf3ce44SJohn Forte 	 * Now check for error attention to indicate the board has been
5180*fcf3ce44SJohn Forte 	 * kiilled
5181*fcf3ce44SJohn Forte 	 */
5182*fcf3ce44SJohn Forte 	j = 0;
5183*fcf3ce44SJohn Forte 	while (j++ < 10000) {
5184*fcf3ce44SJohn Forte 		ha_copy = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
5185*fcf3ce44SJohn Forte 
5186*fcf3ce44SJohn Forte 		if (ha_copy & HA_ERATT) {
5187*fcf3ce44SJohn Forte 			break;
5188*fcf3ce44SJohn Forte 		}
5189*fcf3ce44SJohn Forte 		DELAYUS(50);
5190*fcf3ce44SJohn Forte 	}
5191*fcf3ce44SJohn Forte 
5192*fcf3ce44SJohn Forte 	if (ha_copy & HA_ERATT) {
5193*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5194*fcf3ce44SJohn Forte 		    "Interlock failed. Board killed.");
5195*fcf3ce44SJohn Forte 	} else {
5196*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5197*fcf3ce44SJohn Forte 		    "Interlock failed. Board not killed.");
5198*fcf3ce44SJohn Forte 	}
5199*fcf3ce44SJohn Forte 
5200*fcf3ce44SJohn Forte done:
5201*fcf3ce44SJohn Forte 
5202*fcf3ce44SJohn Forte 	hba->mbox_queue_flag = 0;
5203*fcf3ce44SJohn Forte 
5204*fcf3ce44SJohn Forte 	emlxs_ffstate_change_locked(hba, FC_KILLED);
5205*fcf3ce44SJohn Forte 
5206*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
5207*fcf3ce44SJohn Forte 
5208*fcf3ce44SJohn Forte 	return (FC_SUCCESS);
5209*fcf3ce44SJohn Forte 
5210*fcf3ce44SJohn Forte } /* emlxs_interlock() */
5211*fcf3ce44SJohn Forte 
5212*fcf3ce44SJohn Forte 
5213*fcf3ce44SJohn Forte 
5214*fcf3ce44SJohn Forte extern uint32_t
5215*fcf3ce44SJohn Forte emlxs_hba_reset(emlxs_hba_t *hba, uint32_t restart, uint32_t skip_post)
5216*fcf3ce44SJohn Forte {
5217*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5218*fcf3ce44SJohn Forte 	MAILBOX *swpmb;
5219*fcf3ce44SJohn Forte 	MAILBOX *mb;
5220*fcf3ce44SJohn Forte 	uint32_t word0;
5221*fcf3ce44SJohn Forte 	uint16_t cfg_value;
5222*fcf3ce44SJohn Forte 	uint32_t status;
5223*fcf3ce44SJohn Forte 	uint32_t status1;
5224*fcf3ce44SJohn Forte 	uint32_t status2;
5225*fcf3ce44SJohn Forte 	uint32_t i;
5226*fcf3ce44SJohn Forte 	uint32_t ready;
5227*fcf3ce44SJohn Forte 	emlxs_port_t *vport;
5228*fcf3ce44SJohn Forte 	RING *rp;
5229*fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
5230*fcf3ce44SJohn Forte 
5231*fcf3ce44SJohn Forte 	i = 0;
5232*fcf3ce44SJohn Forte 
5233*fcf3ce44SJohn Forte 	if (!cfg[CFG_RESET_ENABLE].current) {
5234*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
5235*fcf3ce44SJohn Forte 		    "Adapter reset disabled.");
5236*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_ERROR);
5237*fcf3ce44SJohn Forte 
5238*fcf3ce44SJohn Forte 		return (1);
5239*fcf3ce44SJohn Forte 	}
5240*fcf3ce44SJohn Forte 	/* Make sure we have called interlock */
5241*fcf3ce44SJohn Forte 	(void) emlxs_interlock(hba);
5242*fcf3ce44SJohn Forte 
5243*fcf3ce44SJohn Forte 	if (restart) {
5244*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "Restarting.");
5245*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_INIT_START);
5246*fcf3ce44SJohn Forte 
5247*fcf3ce44SJohn Forte 		ready = (HS_FFRDY | HS_MBRDY);
5248*fcf3ce44SJohn Forte 	} else {
5249*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "Resetting.");
5250*fcf3ce44SJohn Forte 		emlxs_ffstate_change(hba, FC_WARM_START);
5251*fcf3ce44SJohn Forte 
5252*fcf3ce44SJohn Forte 		ready = HS_MBRDY;
5253*fcf3ce44SJohn Forte 	}
5254*fcf3ce44SJohn Forte 
5255*fcf3ce44SJohn Forte 	hba->flag &= ~(FC_SLIM2_MODE | FC_HARDWARE_ERROR);
5256*fcf3ce44SJohn Forte 
5257*fcf3ce44SJohn Forte 	mb = FC_SLIM1_MAILBOX(hba);
5258*fcf3ce44SJohn Forte 	swpmb = (MAILBOX *) & word0;
5259*fcf3ce44SJohn Forte 
5260*fcf3ce44SJohn Forte reset:
5261*fcf3ce44SJohn Forte 
5262*fcf3ce44SJohn Forte 	/* Save reset time */
5263*fcf3ce44SJohn Forte 	HBASTATS.ResetTime = hba->timer_tics;
5264*fcf3ce44SJohn Forte 
5265*fcf3ce44SJohn Forte 	if (restart) {
5266*fcf3ce44SJohn Forte 		/* First put restart command in mailbox */
5267*fcf3ce44SJohn Forte 		word0 = 0;
5268*fcf3ce44SJohn Forte 		swpmb->mbxCommand = MBX_RESTART;
5269*fcf3ce44SJohn Forte 		swpmb->mbxHc = 1;
5270*fcf3ce44SJohn Forte 		WRITE_SLIM_ADDR(hba, ((volatile uint32_t *) mb), word0);
5271*fcf3ce44SJohn Forte 
5272*fcf3ce44SJohn Forte 		/* Only skip post after emlxs_ffinit is completed  */
5273*fcf3ce44SJohn Forte 		if (skip_post) {
5274*fcf3ce44SJohn Forte 			WRITE_SLIM_ADDR(hba,
5275*fcf3ce44SJohn Forte 			    (((volatile uint32_t *)mb) + 1), 1);
5276*fcf3ce44SJohn Forte 		} else {
5277*fcf3ce44SJohn Forte 			WRITE_SLIM_ADDR(hba,
5278*fcf3ce44SJohn Forte 			    (((volatile uint32_t *)mb) + 1), 0);
5279*fcf3ce44SJohn Forte 		}
5280*fcf3ce44SJohn Forte 
5281*fcf3ce44SJohn Forte 	}
5282*fcf3ce44SJohn Forte 	/*
5283*fcf3ce44SJohn Forte 	 * Turn off SERR, PERR in PCI cmd register
5284*fcf3ce44SJohn Forte 	 */
5285*fcf3ce44SJohn Forte 	cfg_value = ddi_get16(hba->pci_acc_handle,
5286*fcf3ce44SJohn Forte 	    (uint16_t *)(hba->pci_addr + PCI_COMMAND_REGISTER));
5287*fcf3ce44SJohn Forte 
5288*fcf3ce44SJohn Forte 	(void) ddi_put16(hba->pci_acc_handle,
5289*fcf3ce44SJohn Forte 	    (uint16_t *)(hba->pci_addr + PCI_COMMAND_REGISTER),
5290*fcf3ce44SJohn Forte 	    (uint16_t)(cfg_value & ~(CMD_PARITY_CHK | CMD_SERR_ENBL)));
5291*fcf3ce44SJohn Forte 
5292*fcf3ce44SJohn Forte 	hba->hc_copy = HC_INITFF;
5293*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
5294*fcf3ce44SJohn Forte 
5295*fcf3ce44SJohn Forte 	/* Wait 1 msec before restoring PCI config */
5296*fcf3ce44SJohn Forte 	DELAYMS(1);
5297*fcf3ce44SJohn Forte 
5298*fcf3ce44SJohn Forte 	/* Restore PCI cmd register */
5299*fcf3ce44SJohn Forte 	(void) ddi_put16(hba->pci_acc_handle,
5300*fcf3ce44SJohn Forte 	    (uint16_t *)(hba->pci_addr + PCI_COMMAND_REGISTER),
5301*fcf3ce44SJohn Forte 	    (uint16_t)cfg_value);
5302*fcf3ce44SJohn Forte 
5303*fcf3ce44SJohn Forte 	/* Wait 3 seconds before checking */
5304*fcf3ce44SJohn Forte 	DELAYMS(3000);
5305*fcf3ce44SJohn Forte 	i += 3;
5306*fcf3ce44SJohn Forte 
5307*fcf3ce44SJohn Forte 	/* Wait for reset completion */
5308*fcf3ce44SJohn Forte 	while (i < 30) {
5309*fcf3ce44SJohn Forte 		/* Check status register to see what current state is */
5310*fcf3ce44SJohn Forte 		status = READ_CSR_REG(hba, FC_HS_REG(hba, hba->csr_addr));
5311*fcf3ce44SJohn Forte 
5312*fcf3ce44SJohn Forte 		/* Check to see if any errors occurred during init */
5313*fcf3ce44SJohn Forte 		if (status & HS_FFERM) {
5314*fcf3ce44SJohn Forte 			status1 = READ_SLIM_ADDR(hba,
5315*fcf3ce44SJohn Forte 			    ((volatile uint8_t *) hba->slim_addr + 0xa8));
5316*fcf3ce44SJohn Forte 			status2 = READ_SLIM_ADDR(hba,
5317*fcf3ce44SJohn Forte 			    ((volatile uint8_t *) hba->slim_addr + 0xac));
5318*fcf3ce44SJohn Forte 
5319*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
5320*fcf3ce44SJohn Forte 			    "HS_FFERM: status=0x%x status1=0x%x status2=0x%x",
5321*fcf3ce44SJohn Forte 			    status, status1, status2);
5322*fcf3ce44SJohn Forte 
5323*fcf3ce44SJohn Forte 			emlxs_ffstate_change(hba, FC_ERROR);
5324*fcf3ce44SJohn Forte 			return (1);
5325*fcf3ce44SJohn Forte 		}
5326*fcf3ce44SJohn Forte 		if ((status & ready) == ready) {
5327*fcf3ce44SJohn Forte 			/* Reset Done !! */
5328*fcf3ce44SJohn Forte 			goto done;
5329*fcf3ce44SJohn Forte 		}
5330*fcf3ce44SJohn Forte 		/*
5331*fcf3ce44SJohn Forte 		 * Check every 1 second for 15 seconds, then reset board
5332*fcf3ce44SJohn Forte 		 * again (w/post), then check every 1 second for 15 seconds.
5333*fcf3ce44SJohn Forte 		 */
5334*fcf3ce44SJohn Forte 		DELAYMS(1000);
5335*fcf3ce44SJohn Forte 		i++;
5336*fcf3ce44SJohn Forte 
5337*fcf3ce44SJohn Forte 		/* Reset again (w/post) at 15 seconds */
5338*fcf3ce44SJohn Forte 		if (i == 15) {
5339*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5340*fcf3ce44SJohn Forte 			    "Reset failed. Retrying...");
5341*fcf3ce44SJohn Forte 
5342*fcf3ce44SJohn Forte 			goto reset;
5343*fcf3ce44SJohn Forte 		}
5344*fcf3ce44SJohn Forte 	}
5345*fcf3ce44SJohn Forte 
5346*fcf3ce44SJohn Forte 	/* Timeout occurred */
5347*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
5348*fcf3ce44SJohn Forte 	    "Timeout: status=0x%x", status);
5349*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_ERROR);
5350*fcf3ce44SJohn Forte 
5351*fcf3ce44SJohn Forte 	/* Log a dump event */
5352*fcf3ce44SJohn Forte 	emlxs_log_dump_event(port, NULL, 0);
5353*fcf3ce44SJohn Forte 
5354*fcf3ce44SJohn Forte 	return (1);
5355*fcf3ce44SJohn Forte 
5356*fcf3ce44SJohn Forte done:
5357*fcf3ce44SJohn Forte 
5358*fcf3ce44SJohn Forte 	/* Reset the hba structure */
5359*fcf3ce44SJohn Forte 	hba->flag &= FC_RESET_MASK;
5360*fcf3ce44SJohn Forte 	bzero(hba->ring_tx_count, sizeof (hba->ring_tx_count));
5361*fcf3ce44SJohn Forte 	bzero(hba->io_count, sizeof (hba->io_count));
5362*fcf3ce44SJohn Forte 	hba->iodone_count = 0;
5363*fcf3ce44SJohn Forte 	hba->topology = 0;
5364*fcf3ce44SJohn Forte 	hba->linkspeed = 0;
5365*fcf3ce44SJohn Forte 	hba->heartbeat_active = 0;
5366*fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
5367*fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
5368*fcf3ce44SJohn Forte 	hba->loopback_tics = 0;
5369*fcf3ce44SJohn Forte 
5370*fcf3ce44SJohn Forte 	/* Initialize hc_copy */
5371*fcf3ce44SJohn Forte 	hba->hc_copy = READ_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr));
5372*fcf3ce44SJohn Forte 
5373*fcf3ce44SJohn Forte 	/* Reset the ring objects */
5374*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_RINGS; i++) {
5375*fcf3ce44SJohn Forte 		rp = &hba->ring[i];
5376*fcf3ce44SJohn Forte 		rp->fc_mpon = 0;
5377*fcf3ce44SJohn Forte 		rp->fc_mpoff = 0;
5378*fcf3ce44SJohn Forte 	}
5379*fcf3ce44SJohn Forte 
5380*fcf3ce44SJohn Forte 	/* Reset the port objects */
5381*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
5382*fcf3ce44SJohn Forte 		vport = &VPORT(i);
5383*fcf3ce44SJohn Forte 
5384*fcf3ce44SJohn Forte 		vport->flag &= EMLXS_PORT_RESET_MASK;
5385*fcf3ce44SJohn Forte 		vport->did = 0;
5386*fcf3ce44SJohn Forte 		vport->prev_did = 0;
5387*fcf3ce44SJohn Forte 		vport->lip_type = 0;
5388*fcf3ce44SJohn Forte 		bzero(&vport->fabric_sparam, sizeof (SERV_PARM));
5389*fcf3ce44SJohn Forte 
5390*fcf3ce44SJohn Forte 		bzero((caddr_t)&vport->node_base, sizeof (NODELIST));
5391*fcf3ce44SJohn Forte 		vport->node_base.nlp_Rpi = 0;
5392*fcf3ce44SJohn Forte 		vport->node_base.nlp_DID = 0xffffff;
5393*fcf3ce44SJohn Forte 		vport->node_base.nlp_list_next = NULL;
5394*fcf3ce44SJohn Forte 		vport->node_base.nlp_list_prev = NULL;
5395*fcf3ce44SJohn Forte 		vport->node_base.nlp_active = 1;
5396*fcf3ce44SJohn Forte 		vport->node_count = 0;
5397*fcf3ce44SJohn Forte 
5398*fcf3ce44SJohn Forte 		if (vport->ub_count < EMLXS_UB_TOKEN_OFFSET) {
5399*fcf3ce44SJohn Forte 			vport->ub_count = EMLXS_UB_TOKEN_OFFSET;
5400*fcf3ce44SJohn Forte 		}
5401*fcf3ce44SJohn Forte 	}
5402*fcf3ce44SJohn Forte 
5403*fcf3ce44SJohn Forte 	return (0);
5404*fcf3ce44SJohn Forte 
5405*fcf3ce44SJohn Forte } /* emlxs_hba_reset */
5406*fcf3ce44SJohn Forte 
5407*fcf3ce44SJohn Forte 
5408*fcf3ce44SJohn Forte 
5409*fcf3ce44SJohn Forte extern void
5410*fcf3ce44SJohn Forte emlxs_poll_intr(emlxs_hba_t *hba, uint32_t att_bit)
5411*fcf3ce44SJohn Forte {
5412*fcf3ce44SJohn Forte 	uint32_t ha_copy;
5413*fcf3ce44SJohn Forte 
5414*fcf3ce44SJohn Forte 	/*
5415*fcf3ce44SJohn Forte 	 * Polling a specific attention bit.
5416*fcf3ce44SJohn Forte 	 */
5417*fcf3ce44SJohn Forte 	for (;;) {
5418*fcf3ce44SJohn Forte 		ha_copy = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
5419*fcf3ce44SJohn Forte 
5420*fcf3ce44SJohn Forte 		if (ha_copy & att_bit) {
5421*fcf3ce44SJohn Forte 			break;
5422*fcf3ce44SJohn Forte 		}
5423*fcf3ce44SJohn Forte 	}
5424*fcf3ce44SJohn Forte 
5425*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
5426*fcf3ce44SJohn Forte 	ha_copy = emlxs_get_attention(hba, -1);
5427*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
5428*fcf3ce44SJohn Forte 
5429*fcf3ce44SJohn Forte 	/* Process the attentions */
5430*fcf3ce44SJohn Forte 	emlxs_proc_attention(hba, ha_copy);
5431*fcf3ce44SJohn Forte 
5432*fcf3ce44SJohn Forte 	return;
5433*fcf3ce44SJohn Forte 
5434*fcf3ce44SJohn Forte } /* emlxs_poll_intr() */
5435*fcf3ce44SJohn Forte 
5436*fcf3ce44SJohn Forte 
5437*fcf3ce44SJohn Forte extern uint32_t
5438*fcf3ce44SJohn Forte emlxs_reset_ring(emlxs_hba_t *hba, uint32_t ringno)
5439*fcf3ce44SJohn Forte {
5440*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5441*fcf3ce44SJohn Forte 	RING *rp;
5442*fcf3ce44SJohn Forte 	MAILBOX *mb;
5443*fcf3ce44SJohn Forte 	PGP *pgp;
5444*fcf3ce44SJohn Forte 	off_t offset;
5445*fcf3ce44SJohn Forte 	NODELIST *ndlp;
5446*fcf3ce44SJohn Forte 	uint32_t i;
5447*fcf3ce44SJohn Forte 	emlxs_port_t *vport;
5448*fcf3ce44SJohn Forte 
5449*fcf3ce44SJohn Forte 	rp = &hba->ring[ringno];
5450*fcf3ce44SJohn Forte 	pgp = (PGP *) & ((SLIM2 *) hba->slim2.virt)->mbx.us.s2.port[ringno];
5451*fcf3ce44SJohn Forte 
5452*fcf3ce44SJohn Forte 	if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == 0) {
5453*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ring_reset_msg,
5454*fcf3ce44SJohn Forte 		    "%s: Unable to allocate mailbox buffer.",
5455*fcf3ce44SJohn Forte 		    emlxs_ring_xlate(ringno));
5456*fcf3ce44SJohn Forte 
5457*fcf3ce44SJohn Forte 		return ((uint32_t)FC_FAILURE);
5458*fcf3ce44SJohn Forte 	}
5459*fcf3ce44SJohn Forte 	emlxs_mb_reset_ring(hba, mb, ringno);
5460*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
5461*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ring_reset_msg,
5462*fcf3ce44SJohn Forte 		    "%s: Unable to reset ring. Mailbox cmd=%x status=%x",
5463*fcf3ce44SJohn Forte 		    emlxs_ring_xlate(ringno), mb->mbxCommand, mb->mbxStatus);
5464*fcf3ce44SJohn Forte 
5465*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
5466*fcf3ce44SJohn Forte 		return ((uint32_t)FC_FAILURE);
5467*fcf3ce44SJohn Forte 	}
5468*fcf3ce44SJohn Forte 	/* Free the mailbox */
5469*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
5470*fcf3ce44SJohn Forte 
5471*fcf3ce44SJohn Forte 	/* Update the response ring indicies */
5472*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)&(pgp->rspPutInx) -
5473*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
5474*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
5475*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
5476*fcf3ce44SJohn Forte 	rp->fc_rspidx = rp->fc_port_rspidx = PCIMEM_LONG(pgp->rspPutInx);
5477*fcf3ce44SJohn Forte 
5478*fcf3ce44SJohn Forte 	/* Update the command ring indicies */
5479*fcf3ce44SJohn Forte 	offset = (off_t)((uint64_t)(unsigned long)&(pgp->cmdGetInx) -
5480*fcf3ce44SJohn Forte 	    (uint64_t)(unsigned long)hba->slim2.virt);
5481*fcf3ce44SJohn Forte 	emlxs_mpdata_sync(hba->slim2.dma_handle, offset, 4,
5482*fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
5483*fcf3ce44SJohn Forte 	rp->fc_cmdidx = rp->fc_port_cmdidx = PCIMEM_LONG(pgp->cmdGetInx);
5484*fcf3ce44SJohn Forte 
5485*fcf3ce44SJohn Forte 
5486*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
5487*fcf3ce44SJohn Forte 		vport = &VPORT(i);
5488*fcf3ce44SJohn Forte 
5489*fcf3ce44SJohn Forte 		if (!(vport->flag & EMLXS_PORT_BOUND)) {
5490*fcf3ce44SJohn Forte 			continue;
5491*fcf3ce44SJohn Forte 		}
5492*fcf3ce44SJohn Forte 		/* Clear all node XRI contexts */
5493*fcf3ce44SJohn Forte 		rw_enter(&vport->node_rwlock, RW_WRITER);
5494*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_RINGTX_LOCK);
5495*fcf3ce44SJohn Forte 		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
5496*fcf3ce44SJohn Forte 			ndlp = vport->node_table[i];
5497*fcf3ce44SJohn Forte 			while (ndlp != NULL) {
5498*fcf3ce44SJohn Forte 				ndlp->nlp_flag[FC_IP_RING] &= ~NLP_RPI_XRI;
5499*fcf3ce44SJohn Forte 				ndlp = ndlp->nlp_list_next;
5500*fcf3ce44SJohn Forte 			}
5501*fcf3ce44SJohn Forte 		}
5502*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_RINGTX_LOCK);
5503*fcf3ce44SJohn Forte 		rw_exit(&vport->node_rwlock);
5504*fcf3ce44SJohn Forte 	}
5505*fcf3ce44SJohn Forte 
5506*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ring_reset_msg,
5507*fcf3ce44SJohn Forte 	    "%s", emlxs_ring_xlate(ringno));
5508*fcf3ce44SJohn Forte 
5509*fcf3ce44SJohn Forte 	return (FC_SUCCESS);
5510*fcf3ce44SJohn Forte 
5511*fcf3ce44SJohn Forte } /* emlxs_reset_ring() */
5512*fcf3ce44SJohn Forte 
5513*fcf3ce44SJohn Forte 
5514*fcf3ce44SJohn Forte extern char *
5515*fcf3ce44SJohn Forte emlxs_ffstate_xlate(uint32_t state)
5516*fcf3ce44SJohn Forte {
5517*fcf3ce44SJohn Forte 	static char buffer[32];
5518*fcf3ce44SJohn Forte 	uint32_t i;
5519*fcf3ce44SJohn Forte 	uint32_t count;
5520*fcf3ce44SJohn Forte 
5521*fcf3ce44SJohn Forte 	count = sizeof (emlxs_ffstate_table) / sizeof (emlxs_table_t);
5522*fcf3ce44SJohn Forte 	for (i = 0; i < count; i++) {
5523*fcf3ce44SJohn Forte 		if (state == emlxs_ffstate_table[i].code) {
5524*fcf3ce44SJohn Forte 			return (emlxs_ffstate_table[i].string);
5525*fcf3ce44SJohn Forte 		}
5526*fcf3ce44SJohn Forte 	}
5527*fcf3ce44SJohn Forte 
5528*fcf3ce44SJohn Forte 	(void) sprintf(buffer, "state=0x%x", state);
5529*fcf3ce44SJohn Forte 	return (buffer);
5530*fcf3ce44SJohn Forte 
5531*fcf3ce44SJohn Forte } /* emlxs_ffstate_xlate() */
5532*fcf3ce44SJohn Forte 
5533*fcf3ce44SJohn Forte 
5534*fcf3ce44SJohn Forte extern char *
5535*fcf3ce44SJohn Forte emlxs_ring_xlate(uint32_t ringno)
5536*fcf3ce44SJohn Forte {
5537*fcf3ce44SJohn Forte 	static char buffer[32];
5538*fcf3ce44SJohn Forte 	uint32_t i;
5539*fcf3ce44SJohn Forte 	uint32_t count;
5540*fcf3ce44SJohn Forte 
5541*fcf3ce44SJohn Forte 	count = sizeof (emlxs_ring_table) / sizeof (emlxs_table_t);
5542*fcf3ce44SJohn Forte 	for (i = 0; i < count; i++) {
5543*fcf3ce44SJohn Forte 		if (ringno == emlxs_ring_table[i].code) {
5544*fcf3ce44SJohn Forte 			return (emlxs_ring_table[i].string);
5545*fcf3ce44SJohn Forte 		}
5546*fcf3ce44SJohn Forte 	}
5547*fcf3ce44SJohn Forte 
5548*fcf3ce44SJohn Forte 	(void) sprintf(buffer, "ring=0x%x", ringno);
5549*fcf3ce44SJohn Forte 	return (buffer);
5550*fcf3ce44SJohn Forte 
5551*fcf3ce44SJohn Forte } /* emlxs_ring_xlate() */
5552*fcf3ce44SJohn Forte 
5553*fcf3ce44SJohn Forte 
5554*fcf3ce44SJohn Forte 
5555*fcf3ce44SJohn Forte extern void
5556*fcf3ce44SJohn Forte emlxs_pcix_mxr_update(emlxs_hba_t *hba, uint32_t verbose)
5557*fcf3ce44SJohn Forte {
5558*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5559*fcf3ce44SJohn Forte 	MAILBOX *mb;
5560*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
5561*fcf3ce44SJohn Forte 	uint32_t value;
5562*fcf3ce44SJohn Forte 
5563*fcf3ce44SJohn Forte 	cfg = &CFG;
5564*fcf3ce44SJohn Forte 
5565*fcf3ce44SJohn Forte xlate:
5566*fcf3ce44SJohn Forte 
5567*fcf3ce44SJohn Forte 	switch (cfg[CFG_PCI_MAX_READ].current) {
5568*fcf3ce44SJohn Forte 	case 512:
5569*fcf3ce44SJohn Forte 		value = 0;
5570*fcf3ce44SJohn Forte 		break;
5571*fcf3ce44SJohn Forte 
5572*fcf3ce44SJohn Forte 	case 1024:
5573*fcf3ce44SJohn Forte 		value = 1;
5574*fcf3ce44SJohn Forte 		break;
5575*fcf3ce44SJohn Forte 
5576*fcf3ce44SJohn Forte 	case 2048:
5577*fcf3ce44SJohn Forte 		value = 2;
5578*fcf3ce44SJohn Forte 		break;
5579*fcf3ce44SJohn Forte 
5580*fcf3ce44SJohn Forte 	case 4096:
5581*fcf3ce44SJohn Forte 		value = 3;
5582*fcf3ce44SJohn Forte 		break;
5583*fcf3ce44SJohn Forte 
5584*fcf3ce44SJohn Forte 	default:
5585*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5586*fcf3ce44SJohn Forte 		    "PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
5587*fcf3ce44SJohn Forte 		    cfg[CFG_PCI_MAX_READ].current, cfg[CFG_PCI_MAX_READ].def);
5588*fcf3ce44SJohn Forte 
5589*fcf3ce44SJohn Forte 		cfg[CFG_PCI_MAX_READ].current = cfg[CFG_PCI_MAX_READ].def;
5590*fcf3ce44SJohn Forte 		goto xlate;
5591*fcf3ce44SJohn Forte 	}
5592*fcf3ce44SJohn Forte 
5593*fcf3ce44SJohn Forte 	if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == 0) {
5594*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5595*fcf3ce44SJohn Forte 		    "PCI_MAX_READ: Unable to allocate mailbox buffer.");
5596*fcf3ce44SJohn Forte 		return;
5597*fcf3ce44SJohn Forte 	}
5598*fcf3ce44SJohn Forte 	emlxs_mb_set_var(hba, (MAILBOX *) mb, 0x00100506, value);
5599*fcf3ce44SJohn Forte 
5600*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
5601*fcf3ce44SJohn Forte 		if (verbose || (mb->mbxStatus != 0x12)) {
5602*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5603*fcf3ce44SJohn Forte 			    "PCI_MAX_READ: Unable to update. status=%x "
5604*fcf3ce44SJohn Forte 			    "value=%d (%d bytes)", mb->mbxStatus, value,
5605*fcf3ce44SJohn Forte 			    cfg[CFG_PCI_MAX_READ].current);
5606*fcf3ce44SJohn Forte 		}
5607*fcf3ce44SJohn Forte 	} else {
5608*fcf3ce44SJohn Forte 		if (verbose && (cfg[CFG_PCI_MAX_READ].current !=
5609*fcf3ce44SJohn Forte 		    cfg[CFG_PCI_MAX_READ].def)) {
5610*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5611*fcf3ce44SJohn Forte 			    "PCI_MAX_READ: Updated. %d bytes",
5612*fcf3ce44SJohn Forte 			    cfg[CFG_PCI_MAX_READ].current);
5613*fcf3ce44SJohn Forte 		}
5614*fcf3ce44SJohn Forte 	}
5615*fcf3ce44SJohn Forte 
5616*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
5617*fcf3ce44SJohn Forte 
5618*fcf3ce44SJohn Forte 	return;
5619*fcf3ce44SJohn Forte 
5620*fcf3ce44SJohn Forte } /* emlxs_pcix_mxr_update */
5621*fcf3ce44SJohn Forte 
5622*fcf3ce44SJohn Forte 
5623*fcf3ce44SJohn Forte 
5624*fcf3ce44SJohn Forte extern uint32_t
5625*fcf3ce44SJohn Forte emlxs_get_key(emlxs_hba_t *hba, MAILBOX *mb)
5626*fcf3ce44SJohn Forte {
5627*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5628*fcf3ce44SJohn Forte 	uint32_t npname0, npname1;
5629*fcf3ce44SJohn Forte 	uint32_t tmpkey, theKey;
5630*fcf3ce44SJohn Forte 	uint16_t key850;
5631*fcf3ce44SJohn Forte 	uint32_t t1, t2, t3, t4;
5632*fcf3ce44SJohn Forte 	uint32_t ts;
5633*fcf3ce44SJohn Forte 
5634*fcf3ce44SJohn Forte #define	SEED 0x876EDC21
5635*fcf3ce44SJohn Forte 
5636*fcf3ce44SJohn Forte 	/* This key is only used currently for SBUS adapters */
5637*fcf3ce44SJohn Forte 	if (hba->bus_type != SBUS_FC) {
5638*fcf3ce44SJohn Forte 		return (0);
5639*fcf3ce44SJohn Forte 	}
5640*fcf3ce44SJohn Forte 	tmpkey = mb->un.varWords[30];
5641*fcf3ce44SJohn Forte 	emlxs_ffstate_change(hba, FC_INIT_NVPARAMS);
5642*fcf3ce44SJohn Forte 
5643*fcf3ce44SJohn Forte 	emlxs_mb_read_nv(hba, mb);
5644*fcf3ce44SJohn Forte 	if (emlxs_mb_issue_cmd(hba, mb, MBX_WAIT, 0) != MBX_SUCCESS) {
5645*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
5646*fcf3ce44SJohn Forte 		    "Unable to read nvram. cmd=%x status=%x",
5647*fcf3ce44SJohn Forte 		    mb->mbxCommand, mb->mbxStatus);
5648*fcf3ce44SJohn Forte 
5649*fcf3ce44SJohn Forte 		return (0);
5650*fcf3ce44SJohn Forte 	}
5651*fcf3ce44SJohn Forte 	npname0 = mb->un.varRDnvp.portname[0];
5652*fcf3ce44SJohn Forte 	npname1 = mb->un.varRDnvp.portname[1];
5653*fcf3ce44SJohn Forte 
5654*fcf3ce44SJohn Forte 	key850 = (uint16_t)((tmpkey & 0x00FFFF00) >> 8);
5655*fcf3ce44SJohn Forte 	ts = (uint16_t)(npname1 + 1);
5656*fcf3ce44SJohn Forte 	t1 = ts * key850;
5657*fcf3ce44SJohn Forte 	ts = (uint16_t)((npname1 >> 16) + 1);
5658*fcf3ce44SJohn Forte 	t2 = ts * key850;
5659*fcf3ce44SJohn Forte 	ts = (uint16_t)(npname0 + 1);
5660*fcf3ce44SJohn Forte 	t3 = ts * key850;
5661*fcf3ce44SJohn Forte 	ts = (uint16_t)((npname0 >> 16) + 1);
5662*fcf3ce44SJohn Forte 	t4 = ts * key850;
5663*fcf3ce44SJohn Forte 	theKey = SEED + t1 + t2 + t3 + t4;
5664*fcf3ce44SJohn Forte 
5665*fcf3ce44SJohn Forte 	return (theKey);
5666*fcf3ce44SJohn Forte 
5667*fcf3ce44SJohn Forte } /* emlxs_get_key() */
5668