1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at
9  * http://www.opensource.org/licenses/cddl1.txt.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #define	EMLXS_FW_TABLE_DEF
28 #define	EMLXS_MODEL_DEF
29 
30 #include <emlxs.h>
31 
32 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
33 EMLXS_MSG_DEF(EMLXS_HBA_C);
34 
35 
36 static void emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp,
37     IOCBQ *iocbq);
38 
39 static void emlxs_pci_cap_offsets(emlxs_hba_t *hba);
40 
41 #ifdef MSI_SUPPORT
42 uint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
43 	{EMLXS_MSI_MAP1, EMLXS_MSI_MAP2, EMLXS_MSI_MAP4, EMLXS_MSI_MAP8};
44 uint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
45 	{EMLXS_MSI0_MASK1, EMLXS_MSI0_MASK2, EMLXS_MSI0_MASK4,
46 	EMLXS_MSI0_MASK8};
47 #endif /* MSI_SUPPORT */
48 
49 emlxs_firmware_t emlxs_fw_table[] = EMLXS_FW_TABLE;
50 int emlxs_fw_count = sizeof (emlxs_fw_table) / sizeof (emlxs_firmware_t);
51 
52 emlxs_table_t emlxs_pci_cap[] = {
53 	{PCI_CAP_ID_PM, "PCI_CAP_ID_PM"},
54 	{PCI_CAP_ID_AGP, "PCI_CAP_ID_AGP"},
55 	{PCI_CAP_ID_VPD, "PCI_CAP_ID_VPD"},
56 	{PCI_CAP_ID_SLOT_ID, "PCI_CAP_ID_SLOT_ID"},
57 	{PCI_CAP_ID_MSI, "PCI_CAP_ID_MSI"},
58 	{PCI_CAP_ID_cPCI_HS, "PCI_CAP_ID_cPCI_HS"},
59 	{PCI_CAP_ID_PCIX, "PCI_CAP_ID_PCIX"},
60 	{PCI_CAP_ID_HT, "PCI_CAP_ID_HT"},
61 	{PCI_CAP_ID_VS, "PCI_CAP_ID_VS"},
62 	{PCI_CAP_ID_DEBUG_PORT, "PCI_CAP_ID_DEBUG_PORT"},
63 	{PCI_CAP_ID_cPCI_CRC, "PCI_CAP_ID_cPCI_CRC"},
64 	{PCI_CAP_ID_PCI_HOTPLUG, "PCI_CAP_ID_PCI_HOTPLUG"},
65 	{PCI_CAP_ID_P2P_SUBSYS, "PCI_CAP_ID_P2P_SUBSYS"},
66 	{PCI_CAP_ID_AGP_8X, "PCI_CAP_ID_AGP_8X"},
67 	{PCI_CAP_ID_SECURE_DEV, "PCI_CAP_ID_SECURE_DEV"},
68 	{PCI_CAP_ID_PCI_E, "PCI_CAP_ID_PCI_E"},
69 	{PCI_CAP_ID_MSI_X, "PCI_CAP_ID_MSI_X"},
70 	{PCI_CAP_ID_SATA, "PCI_CAP_ID_SATA"},
71 	{PCI_CAP_ID_FLR, "PCI_CAP_ID_FLR"}
72 
73 }; /* emlxs_pci_cap */
74 
75 emlxs_table_t emlxs_pci_ecap[] = {
76 	{PCIE_EXT_CAP_ID_AER, "PCIE_EXT_CAP_ID_AER"},
77 	{PCIE_EXT_CAP_ID_VC, "PCIE_EXT_CAP_ID_VC"},
78 	{PCIE_EXT_CAP_ID_SER, "PCIE_EXT_CAP_ID_SER"},
79 	{PCIE_EXT_CAP_ID_PWR_BUDGET, "PCIE_EXT_CAP_ID_PWR_BUDGET"},
80 	{PCIE_EXT_CAP_ID_RC_LINK_DECL, "PCIE_EXT_CAP_ID_RC_LINK_DECL"},
81 	{PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "PCIE_EXT_CAP_ID_RC_INT_LINKCTRL"},
82 	{PCIE_EXT_CAP_ID_RC_EVNT_CEA, "PCIE_EXT_CAP_ID_RC_EVNT_CEA"},
83 	{PCIE_EXT_CAP_ID_MFVC, "PCIE_EXT_CAP_ID_MFVC"},
84 	{PCIE_EXT_CAP_ID_VC_WITH_MFVC, "PCIE_EXT_CAP_ID_VC_WITH_MFVC"},
85 	{PCIE_EXT_CAP_ID_RCRB, "PCIE_EXT_CAP_ID_RCRB"},
86 	{PCIE_EXT_CAP_ID_VS, "PCIE_EXT_CAP_ID_VS"},
87 	{PCIE_EXT_CAP_ID_CAC, "PCIE_EXT_CAP_ID_CAC"},
88 	{PCIE_EXT_CAP_ID_ACS, "PCIE_EXT_CAP_ID_ACS"},
89 	{PCIE_EXT_CAP_ID_ARI, "PCIE_EXT_CAP_ID_ARI"},
90 	{PCIE_EXT_CAP_ID_ATS, "PCIE_EXT_CAP_ID_ATS"},
91 	{PCI_EXT_CAP_ID_SRIOV, "PCI_EXT_CAP_ID_SRIOV"},
92 	{PCI_EXT_CAP_ID_TPH, "PCI_EXT_CAP_ID_TPH"},
93 	{PCI_EXT_CAP_ID_SEC_PCI, "PCI_EXT_CAP_ID_SEC_PCI"}
94 
95 }; /* emlxs_pci_ecap */
96 
97 
98 emlxs_table_t emlxs_ring_table[] = {
99 	{FC_FCP_RING, "FCP Ring"},
100 	{FC_IP_RING, "IP  Ring"},
101 	{FC_ELS_RING, "ELS Ring"},
102 	{FC_CT_RING, "CT  Ring"}
103 
104 }; /* emlxs_ring_table */
105 
106 emlxs_table_t emlxs_ffstate_table[] = {
107 	{0, "NULL"},
108 	{FC_ERROR, "ERROR"},
109 	{FC_KILLED, "KILLED"},
110 	{FC_WARM_START, "WARM_START"},
111 	{FC_INIT_START, "INIT_START"},
112 	{FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
113 	{FC_INIT_REV, "INIT_REV"},
114 	{FC_INIT_CFGPORT, "INIT_CFGPORT"},
115 	{FC_INIT_CFGRING, "INIT_CFGRING"},
116 	{FC_INIT_INITLINK, "INIT_INITLINK"},
117 	{FC_LINK_DOWN, "LINK_DOWN"},
118 	{FC_LINK_UP, "LINK_UP"},
119 	{FC_CLEAR_LA, "CLEAR_LA"},
120 	{FC_READY, "READY"}
121 
122 }; /* emlxs_ffstate_table */
123 
124 
125 #ifdef MSI_SUPPORT
126 /* EMLXS_INTR_INIT */
127 int32_t
128 emlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
129 {
130 	emlxs_port_t *port = &PPORT;
131 	int32_t pass = 0;
132 	int32_t type = 0;
133 	char s_type[16];
134 	int32_t types;
135 	int32_t count;
136 	int32_t nintrs;
137 	int32_t mode;
138 	int32_t actual;
139 	int32_t new_actual;
140 	int32_t i;
141 	int32_t ret;
142 	ddi_intr_handle_t *htable = NULL;
143 	ddi_intr_handle_t *new_htable = NULL;
144 	uint32_t *intr_pri = NULL;
145 	int32_t *intr_cap = NULL;
146 	int32_t hilevel_pri;
147 	emlxs_config_t *cfg = &CFG;
148 
149 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
150 		return (emlxs_intx_init(hba, max));
151 	}
152 
153 	if (hba->intr_flags & EMLXS_MSI_INITED) {
154 		return (DDI_SUCCESS);
155 	}
156 
157 	/* Set max interrupt count if not specified */
158 	if (max == 0) {
159 		if ((cfg[CFG_MSI_MODE].current == 2) ||
160 		    (cfg[CFG_MSI_MODE].current == 3)) {
161 			max = EMLXS_MSI_MAX_INTRS;
162 		} else {
163 			max = 1;
164 		}
165 	}
166 
167 	/* Filter max interrupt count with adapter model specification */
168 	if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
169 		max = hba->model_info.intr_limit;
170 	}
171 
172 	/* Get the available interrupt types from the kernel */
173 	types = 0;
174 	ret = ddi_intr_get_supported_types(hba->dip, &types);
175 
176 	if ((ret != DDI_SUCCESS)) {
177 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
178 		    "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
179 
180 		/* Default to fixed type */
181 		types = DDI_INTR_TYPE_FIXED;
182 	}
183 
184 	/* Check if fixed interrupts are being forced */
185 	if (cfg[CFG_MSI_MODE].current == 0) {
186 		types &= DDI_INTR_TYPE_FIXED;
187 	}
188 
189 	/* Check if MSI interrupts are being forced */
190 	else if ((cfg[CFG_MSI_MODE].current == 1) ||
191 	    (cfg[CFG_MSI_MODE].current == 2)) {
192 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
193 	}
194 
195 begin:
196 
197 	/* Set interrupt type and interrupt count */
198 	type = 0;
199 
200 	/* Check if MSIX is fully supported */
201 	if ((types & DDI_INTR_TYPE_MSIX) &&
202 	    (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
203 		/* Get the max interrupt count from the adapter */
204 		nintrs = 0;
205 		ret =
206 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX,
207 		    &nintrs);
208 
209 		if (ret == DDI_SUCCESS && nintrs) {
210 			type = DDI_INTR_TYPE_MSIX;
211 			(void) strlcpy(s_type, "TYPE_MSIX", sizeof (s_type));
212 			goto initialize;
213 		}
214 	}
215 
216 	/* Check if MSI is fully supported */
217 	if ((types & DDI_INTR_TYPE_MSI) &&
218 	    (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
219 		/* Get the max interrupt count from the adapter */
220 		nintrs = 0;
221 		ret =
222 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
223 
224 		if (ret == DDI_SUCCESS && nintrs) {
225 			type = DDI_INTR_TYPE_MSI;
226 			(void) strlcpy(s_type, "TYPE_MSI", sizeof (s_type));
227 			goto initialize;
228 		}
229 	}
230 
231 	/* Check if fixed interrupts are fully supported */
232 	if ((types & DDI_INTR_TYPE_FIXED) &&
233 	    (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
234 		/* Get the max interrupt count from the adapter */
235 		nintrs = 0;
236 		ret =
237 		    ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED,
238 		    &nintrs);
239 
240 		if (ret == DDI_SUCCESS) {
241 			type = DDI_INTR_TYPE_FIXED;
242 			(void) strlcpy(s_type, "TYPE_FIXED", sizeof (s_type));
243 			goto initialize;
244 		}
245 	}
246 
247 	goto init_failed;
248 
249 
250 initialize:
251 
252 	pass++;
253 	mode = 0;
254 	actual = 0;
255 	htable = NULL;
256 	intr_pri = NULL;
257 	intr_cap = NULL;
258 	hilevel_pri = 0;
259 
260 	if (pass == 1) {
261 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
262 		    "MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
263 		    cfg[CFG_MSI_MODE].current, types, nintrs);
264 	}
265 
266 	/* Validate interrupt count */
267 	count = min(nintrs, max);
268 
269 	if (count >= 8) {
270 		count = 8;
271 	} else if (count >= 4) {
272 		count = 4;
273 	} else if (count >= 2) {
274 		count = 2;
275 	} else {
276 		count = 1;
277 	}
278 
279 	/* Allocate an array of interrupt handles */
280 	htable =
281 	    kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)),
282 	    KM_SLEEP);
283 
284 	/* Allocate 'count' interrupts */
285 	ret =
286 	    ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
287 	    &actual, DDI_INTR_ALLOC_NORMAL);
288 
289 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
290 	    "MSI: %s: count=%d actual=%d ret=%d", s_type, count, actual, ret);
291 
292 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
293 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
294 		    "MSI: Unable to allocate interrupts. error=%d", ret);
295 
296 		actual = 0;
297 		goto init_failed;
298 	}
299 
300 	if (actual != count) {
301 		/* Validate actual count */
302 		if (actual >= 8) {
303 			new_actual = 8;
304 		} else if (actual >= 4) {
305 			new_actual = 4;
306 		} else if (actual >= 2) {
307 			new_actual = 2;
308 		} else {
309 			new_actual = 1;
310 		}
311 
312 		if (new_actual < actual) {
313 			/* Free extra handles */
314 			for (i = new_actual; i < actual; i++) {
315 				(void) ddi_intr_free(htable[i]);
316 			}
317 
318 			actual = new_actual;
319 		}
320 
321 		/* Allocate a new array of interrupt handles */
322 		new_htable =
323 		    kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
324 		    KM_SLEEP);
325 
326 		/* Copy old array to new array */
327 		bcopy((uint8_t *)htable, (uint8_t *)new_htable,
328 		    (actual * sizeof (ddi_intr_handle_t)));
329 
330 		/* Free the old array */
331 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
332 
333 		htable = new_htable;
334 		count = actual;
335 	}
336 
337 	/* Allocate interrupt priority table */
338 	intr_pri =
339 	    (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
340 	    KM_SLEEP);
341 
342 	/* Allocate interrupt capability table */
343 	intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
344 
345 	/* Get minimum hilevel priority */
346 	hilevel_pri = ddi_intr_get_hilevel_pri();
347 
348 	/* Fill the priority and capability tables */
349 	for (i = 0; i < count; ++i) {
350 		ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
351 
352 		if (ret != DDI_SUCCESS) {
353 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
354 			    "MSI: ddi_intr_get_pri(%d) failed. "
355 			    "handle=%p ret=%d",
356 			    i, &htable[i], ret);
357 
358 			/* Clean up the interrupts */
359 			goto init_failed;
360 		}
361 
362 		if (intr_pri[i] >= hilevel_pri) {
363 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
364 			    "MSI: Interrupt(%d) level too high. "
365 			    "pri=0x%x hilevel=0x%x",
366 			    i, intr_pri[i], hilevel_pri);
367 
368 			/* Clean up the interrupts */
369 			goto init_failed;
370 		}
371 
372 		ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
373 
374 		if (ret != DDI_SUCCESS) {
375 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
376 			    "MSI: ddi_intr_get_cap(%d) failed. "
377 			    "handle=%p ret=%d",
378 			    i, &htable[i], ret);
379 
380 			/* Clean up the interrupts */
381 			goto init_failed;
382 		}
383 
384 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
385 		    "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
386 		    intr_cap[i], intr_pri[i], hilevel_pri);
387 
388 	}
389 
390 	/* Set mode */
391 	switch (count) {
392 	case 8:
393 		mode = EMLXS_MSI_MODE8;
394 		break;
395 
396 	case 4:
397 		mode = EMLXS_MSI_MODE4;
398 		break;
399 
400 	case 2:
401 		mode = EMLXS_MSI_MODE2;
402 		break;
403 
404 	default:
405 		mode = EMLXS_MSI_MODE1;
406 	}
407 
408 	/* Save the info */
409 	hba->intr_htable = htable;
410 	hba->intr_count = count;
411 	hba->intr_pri = intr_pri;
412 	hba->intr_cap = intr_cap;
413 	hba->intr_type = type;
414 	hba->intr_arg = (void *)((unsigned long)intr_pri[0]);
415 	hba->intr_mask = emlxs_msi_mask[mode];
416 
417 	hba->intr_cond = 0;
418 
419 	/* Adjust number of channels based on intr_count */
420 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
421 		hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
422 	}
423 
424 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
425 		hba->intr_map[i] = emlxs_msi_map[mode][i];
426 		hba->intr_cond |= emlxs_msi_map[mode][i];
427 
428 		mutex_init(&hba->intr_lock[i], NULL, MUTEX_DRIVER,
429 		    DDI_INTR_PRI(hba->intr_arg));
430 	}
431 
432 	/* Set flag to indicate support */
433 	hba->intr_flags |= EMLXS_MSI_INITED;
434 
435 	/* Create the interrupt threads */
436 	for (i = 0; i < hba->chan_count; i++) {
437 		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
438 		    DDI_INTR_PRI(hba->intr_arg));
439 
440 		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
441 	}
442 
443 	return (DDI_SUCCESS);
444 
445 init_failed:
446 
447 	if (intr_cap) {
448 		kmem_free(intr_cap, (count * sizeof (int32_t)));
449 	}
450 
451 	if (intr_pri) {
452 		kmem_free(intr_pri, (count * sizeof (int32_t)));
453 	}
454 
455 	if (htable) {
456 		/* Process the interrupt handlers */
457 		for (i = 0; i < actual; i++) {
458 			/* Free the handle[i] */
459 			(void) ddi_intr_free(htable[i]);
460 		}
461 
462 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
463 	}
464 
465 	/* Initialize */
466 	hba->intr_htable = NULL;
467 	hba->intr_count = 0;
468 	hba->intr_pri = NULL;
469 	hba->intr_cap = NULL;
470 	hba->intr_type = 0;
471 	hba->intr_arg = NULL;
472 	hba->intr_cond = 0;
473 	bzero(hba->intr_map, sizeof (hba->intr_map));
474 	bzero(hba->intr_lock, sizeof (hba->intr_lock));
475 
476 	if (type == DDI_INTR_TYPE_MSIX) {
477 		types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
478 		goto begin;
479 	} else if (type == DDI_INTR_TYPE_MSI) {
480 		types &= DDI_INTR_TYPE_FIXED;
481 		goto begin;
482 	}
483 
484 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
485 	    "MSI: Unable to initialize interrupts");
486 
487 	return (DDI_FAILURE);
488 
489 
490 } /* emlxs_msi_init() */
491 
492 
493 /* EMLXS_INTR_UNINIT */
494 int32_t
495 emlxs_msi_uninit(emlxs_hba_t *hba)
496 {
497 	uint32_t count;
498 	int32_t i;
499 	ddi_intr_handle_t *htable;
500 	uint32_t *intr_pri;
501 	int32_t *intr_cap;
502 	int32_t ret;
503 
504 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
505 		return (emlxs_intx_uninit(hba));
506 	}
507 
508 	/*
509 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
510 	 *    "MSI: msi_uninit called. flags=%x",
511 	 *    hba->intr_flags);
512 	 */
513 
514 	/* Make sure interrupts have been removed first */
515 	if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
516 		ret = emlxs_msi_remove(hba);
517 
518 		if (ret != DDI_SUCCESS) {
519 			return (ret);
520 		}
521 	}
522 
523 	/* Check if the interrupts are still initialized */
524 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
525 		return (DDI_SUCCESS);
526 	}
527 	hba->intr_flags &= ~EMLXS_MSI_INITED;
528 
529 	/* Get handle table parameters */
530 	htable = hba->intr_htable;
531 	count = hba->intr_count;
532 	intr_pri = hba->intr_pri;
533 	intr_cap = hba->intr_cap;
534 
535 	/* Clean up */
536 	hba->intr_count = 0;
537 	hba->intr_htable = NULL;
538 	hba->intr_pri = NULL;
539 	hba->intr_cap = NULL;
540 	hba->intr_type = 0;
541 	hba->intr_arg = NULL;
542 	hba->intr_cond = 0;
543 	bzero(hba->intr_map, sizeof (hba->intr_map));
544 
545 	if (intr_cap) {
546 		kmem_free(intr_cap, (count * sizeof (int32_t)));
547 	}
548 
549 	if (intr_pri) {
550 		kmem_free(intr_pri, (count * sizeof (int32_t)));
551 	}
552 
553 	if (htable) {
554 		/* Process the interrupt handlers */
555 		for (i = 0; i < count; ++i) {
556 			/* Free the handle[i] */
557 			ret = ddi_intr_free(htable[i]);
558 		}
559 
560 		kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
561 	}
562 
563 	/* Destroy the intr locks */
564 	for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
565 		mutex_destroy(&hba->intr_lock[i]);
566 	}
567 
568 	/* Destroy the interrupt threads */
569 	for (i = 0; i < hba->chan_count; i++) {
570 		emlxs_thread_destroy(&hba->chan[i].intr_thread);
571 		mutex_destroy(&hba->chan[i].rsp_lock);
572 	}
573 
574 	/*
575 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
576 	 *    "MSI: msi_uninit done. flags=%x",
577 	 *    hba->intr_flags);
578 	 */
579 
580 	return (DDI_SUCCESS);
581 
582 } /* emlxs_msi_uninit() */
583 
584 
585 /* EMLXS_INTR_ADD */
586 int32_t
587 emlxs_msi_add(emlxs_hba_t *hba)
588 {
589 	emlxs_port_t *port = &PPORT;
590 	int32_t count;
591 	int32_t i;
592 	int32_t ret;
593 	ddi_intr_handle_t *htable = NULL;
594 	int32_t *intr_cap = NULL;
595 
596 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
597 		return (emlxs_intx_add(hba));
598 	}
599 
600 	/* Check if interrupts have already been added */
601 	if (hba->intr_flags & EMLXS_MSI_ADDED) {
602 		return (DDI_SUCCESS);
603 	}
604 
605 	/* Check if interrupts have been initialized */
606 	if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
607 		ret = emlxs_msi_init(hba, 0);
608 
609 		if (ret != DDI_SUCCESS) {
610 			return (ret);
611 		}
612 	}
613 
614 	/* Get handle table parameters */
615 	htable = hba->intr_htable;
616 	count = hba->intr_count;
617 	intr_cap = hba->intr_cap;
618 
619 	/* Add the interrupt handlers */
620 	for (i = 0; i < count; ++i) {
621 		/* add handler for handle[i] */
622 		ret =
623 		    ddi_intr_add_handler(htable[i], EMLXS_SLI_MSI_INTR,
624 		    (char *)hba, (char *)((unsigned long)i));
625 
626 		if (ret != DDI_SUCCESS) {
627 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
628 			    "MSI: ddi_intr_add_handler(%d) failed. "
629 			    "handle=%p ret=%d",
630 			    i, &htable[i], ret);
631 
632 			/* Process the remaining interrupt handlers */
633 			while (i) {
634 				/* Decrement i */
635 				i--;
636 
637 				/* Remove the handler */
638 				ret = ddi_intr_remove_handler(htable[i]);
639 
640 			}
641 
642 			return (DDI_FAILURE);
643 		}
644 	}
645 
646 	/* Enable the interrupts */
647 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
648 		ret = ddi_intr_block_enable(htable, count);
649 
650 		if (ret != DDI_SUCCESS) {
651 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
652 			    "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
653 			    count, ret);
654 
655 			for (i = 0; i < count; ++i) {
656 				ret = ddi_intr_enable(htable[i]);
657 
658 				if (ret != DDI_SUCCESS) {
659 					EMLXS_MSGF(EMLXS_CONTEXT,
660 					    &emlxs_init_debug_msg,
661 					    "MSI: ddi_intr_enable(%d) failed. "
662 					    "ret=%d",
663 					    i, ret);
664 				}
665 			}
666 		}
667 	} else {
668 		for (i = 0; i < count; ++i) {
669 			ret = ddi_intr_enable(htable[i]);
670 
671 			if (ret != DDI_SUCCESS) {
672 				EMLXS_MSGF(EMLXS_CONTEXT,
673 				    &emlxs_init_debug_msg,
674 				    "MSI: ddi_intr_enable(%d) failed. ret=%d",
675 				    i, ret);
676 			}
677 		}
678 	}
679 
680 
681 	/* Set flag to indicate support */
682 	hba->intr_flags |= EMLXS_MSI_ADDED;
683 
684 	return (DDI_SUCCESS);
685 
686 } /* emlxs_msi_add() */
687 
688 
689 
690 /* EMLXS_INTR_REMOVE */
691 int32_t
692 emlxs_msi_remove(emlxs_hba_t *hba)
693 {
694 	emlxs_port_t *port = &PPORT;
695 	uint32_t count;
696 	int32_t i;
697 	ddi_intr_handle_t *htable;
698 	int32_t *intr_cap;
699 	int32_t ret;
700 
701 	if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
702 		return (emlxs_intx_remove(hba));
703 	}
704 
705 	/*
706 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
707 	 *    "MSI: msi_remove called. flags=%x",
708 	 *    hba->intr_flags);
709 	 */
710 
711 	/* Check if interrupts have already been removed */
712 	if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
713 		return (DDI_SUCCESS);
714 	}
715 	hba->intr_flags &= ~EMLXS_MSI_ADDED;
716 
717 	/* Disable all adapter interrupts */
718 	EMLXS_SLI_DISABLE_INTR(hba, 0);
719 
720 	/* Get handle table parameters */
721 	htable = hba->intr_htable;
722 	count = hba->intr_count;
723 	intr_cap = hba->intr_cap;
724 
725 	/* Disable the interrupts */
726 	if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
727 		ret = ddi_intr_block_disable(htable, count);
728 
729 		if (ret != DDI_SUCCESS) {
730 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
731 			    "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
732 			    count, ret);
733 
734 			for (i = 0; i < count; i++) {
735 				ret = ddi_intr_disable(htable[i]);
736 
737 				if (ret != DDI_SUCCESS) {
738 					EMLXS_MSGF(EMLXS_CONTEXT,
739 					    &emlxs_init_debug_msg,
740 					    "MSI: ddi_intr_disable(%d) failed. "
741 					    "ret=%d",
742 					    i, ret);
743 				}
744 			}
745 		}
746 	} else {
747 		for (i = 0; i < count; i++) {
748 			ret = ddi_intr_disable(htable[i]);
749 
750 			if (ret != DDI_SUCCESS) {
751 				EMLXS_MSGF(EMLXS_CONTEXT,
752 				    &emlxs_init_debug_msg,
753 				    "MSI: ddi_intr_disable(%d) failed. ret=%d",
754 				    i, ret);
755 			}
756 		}
757 	}
758 
759 	/* Process the interrupt handlers */
760 	for (i = 0; i < count; i++) {
761 		/* Remove the handler */
762 		ret = ddi_intr_remove_handler(htable[i]);
763 
764 
765 	}
766 
767 	return (DDI_SUCCESS);
768 
769 } /* emlxs_msi_remove() */
770 
771 #endif /* MSI_SUPPORT */
772 
773 
774 /* EMLXS_INTR_INIT */
775 /* ARGSUSED */
776 int32_t
777 emlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
778 {
779 	emlxs_port_t *port = &PPORT;
780 	emlxs_config_t *cfg = &CFG;
781 	int32_t ret;
782 	uint32_t i;
783 
784 	/* Check if interrupts have already been initialized */
785 	if (hba->intr_flags & EMLXS_INTX_INITED) {
786 		return (DDI_SUCCESS);
787 	}
788 
789 	/* Check if adapter is flagged for INTX support */
790 	if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
791 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
792 		    "INTX: %s does not support INTX.  flags=0x%x",
793 		    hba->model_info.model, hba->model_info.flags);
794 
795 		return (DDI_FAILURE);
796 	}
797 
798 	/*
799 	 * Interrupt number '0' is a high-level interrupt. This driver
800 	 * does not support having its interrupts mapped above scheduler
801 	 * priority; i.e., we always expect to be able to call general
802 	 * kernel routines that may invoke the scheduler.
803 	 */
804 	if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
805 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
806 		    "INTX: High-level interrupt not supported.");
807 
808 		return (DDI_FAILURE);
809 	}
810 
811 	/* Get an iblock cookie */
812 	ret =
813 	    ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
814 	    (ddi_iblock_cookie_t *)&hba->intr_arg);
815 	if (ret != DDI_SUCCESS) {
816 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
817 		    "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
818 
819 		return (ret);
820 	}
821 
822 	hba->intr_flags |= EMLXS_INTX_INITED;
823 
824 	hba->intr_count = 1;
825 	/* Adjust number of channels based on intr_count */
826 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
827 		hba->chan_count = cfg[CFG_NUM_WQ].current;
828 	}
829 
830 	/* Create the interrupt threads */
831 	for (i = 0; i < hba->chan_count; i++) {
832 		mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
833 		    DDI_INTR_PRI(hba->intr_arg));
834 
835 		emlxs_thread_create(hba, &hba->chan[i].intr_thread);
836 	}
837 
838 	return (DDI_SUCCESS);
839 
840 } /* emlxs_intx_init() */
841 
842 
843 /* EMLXS_INTR_UNINIT */
844 int32_t
845 emlxs_intx_uninit(emlxs_hba_t *hba)
846 {
847 	int32_t ret;
848 	uint32_t i;
849 
850 	/* Make sure interrupts have been removed */
851 	if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
852 		ret = emlxs_intx_remove(hba);
853 
854 		if (ret != DDI_SUCCESS) {
855 			return (ret);
856 		}
857 	}
858 
859 	/* Check if the interrupts are still initialized */
860 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
861 		return (DDI_SUCCESS);
862 	}
863 	hba->intr_flags &= ~EMLXS_INTX_INITED;
864 
865 	hba->intr_arg = NULL;
866 
867 	/* Create the interrupt threads */
868 	for (i = 0; i < hba->chan_count; i++) {
869 		emlxs_thread_destroy(&hba->chan[i].intr_thread);
870 		mutex_destroy(&hba->chan[i].rsp_lock);
871 	}
872 
873 	return (DDI_SUCCESS);
874 
875 } /* emlxs_intx_uninit() */
876 
877 
878 /*
879  * This is the legacy method for adding interrupts in Solaris
880  * EMLXS_INTR_ADD
881  */
882 int32_t
883 emlxs_intx_add(emlxs_hba_t *hba)
884 {
885 	emlxs_port_t *port = &PPORT;
886 	int32_t ret;
887 
888 	/* Check if interrupts have already been added */
889 	if (hba->intr_flags & EMLXS_INTX_ADDED) {
890 		return (DDI_SUCCESS);
891 	}
892 
893 	/* Check if interrupts have been initialized */
894 	if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
895 		ret = emlxs_intx_init(hba, 0);
896 
897 		if (ret != DDI_SUCCESS) {
898 			return (ret);
899 		}
900 	}
901 
902 	/* add intrrupt handler routine */
903 	ret = ddi_add_intr((void *)hba->dip,
904 	    (uint_t)EMLXS_INUMBER,
905 	    (ddi_iblock_cookie_t *)&hba->intr_arg,
906 	    (ddi_idevice_cookie_t *)0,
907 	    (uint_t(*)())EMLXS_SLI_INTX_INTR, (caddr_t)hba);
908 
909 	if (ret != DDI_SUCCESS) {
910 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
911 		    "INTX: ddi_add_intr failed. ret=%d", ret);
912 
913 		return (ret);
914 	}
915 
916 	hba->intr_flags |= EMLXS_INTX_ADDED;
917 
918 	return (DDI_SUCCESS);
919 
920 } /* emlxs_intx_add() */
921 
922 
923 /* EMLXS_INTR_REMOVE */
924 int32_t
925 emlxs_intx_remove(emlxs_hba_t *hba)
926 {
927 	/* Check if interrupts have already been removed */
928 	if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
929 		return (DDI_SUCCESS);
930 	}
931 	hba->intr_flags &= ~EMLXS_INTX_ADDED;
932 
933 	/* Diable all adapter interrupts */
934 	EMLXS_SLI_DISABLE_INTR(hba, 0);
935 
936 	/* Remove the interrupt */
937 	(void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
938 	    hba->intr_arg);
939 
940 	return (DDI_SUCCESS);
941 
942 } /* emlxs_intx_remove() */
943 
944 
945 extern void
946 emlxs_process_link_speed(emlxs_hba_t *hba)
947 {
948 	emlxs_vpd_t *vpd;
949 	emlxs_config_t *cfg;
950 	uint32_t hi;
951 
952 	/*
953 	 * This routine modifies the link-speed config parameter entry
954 	 * based on adapter capabilities
955 	 */
956 	vpd = &VPD;
957 	cfg = &hba->config[CFG_LINK_SPEED];
958 
959 	(void) strlcpy(cfg->help, "Select link speed. [0=Auto",
960 	    EMLXS_CFG_HELP_SIZE);
961 	hi = 0;
962 
963 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
964 		(void) strlcat(cfg->help, ", 1=1Gb", EMLXS_CFG_HELP_SIZE);
965 		hi = 1;
966 	}
967 
968 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
969 		(void) strlcat(cfg->help, ", 2=2Gb", EMLXS_CFG_HELP_SIZE);
970 		hi = 2;
971 	}
972 
973 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
974 		(void) strlcat(cfg->help, ", 4=4Gb", EMLXS_CFG_HELP_SIZE);
975 		hi = 4;
976 	}
977 
978 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
979 		(void) strlcat(cfg->help, ", 8=8Gb", EMLXS_CFG_HELP_SIZE);
980 		hi = 8;
981 	}
982 
983 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
984 		(void) strlcat(cfg->help, ", 10=10Gb", EMLXS_CFG_HELP_SIZE);
985 		hi = 10;
986 	}
987 
988 	if (vpd->link_speed & LMT_16GB_CAPABLE) {
989 		(void) strlcat(cfg->help, ", 16=16Gb", EMLXS_CFG_HELP_SIZE);
990 		hi = 16;
991 	}
992 
993 	(void) strlcat(cfg->help, "]", EMLXS_CFG_HELP_SIZE);
994 	cfg->hi = hi;
995 
996 	/* Now revalidate the current parameter setting */
997 	cfg->current = emlxs_check_parm(hba, CFG_LINK_SPEED, cfg->current);
998 
999 	return;
1000 
1001 } /* emlxs_process_link_speed() */
1002 
1003 
1004 /*
1005  * emlxs_parse_vpd()
1006  *
1007  * This routine will parse the VPD data
1008  */
1009 extern int
1010 emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd_buf, uint32_t size)
1011 {
1012 	emlxs_port_t *port = &PPORT;
1013 	char tag[3];
1014 	uint8_t lenlo, lenhi;
1015 	uint32_t n;
1016 	uint16_t block_size;
1017 	uint32_t block_index = 0;
1018 	uint8_t sub_size;
1019 	uint32_t sub_index;
1020 	int32_t finished = 0;
1021 	int32_t index = 0;
1022 	char buffer[128];
1023 	emlxs_vpd_t *vpd;
1024 
1025 	vpd = &VPD;
1026 
1027 
1028 	while (!finished && (block_index < size)) {
1029 		/*
1030 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1031 		 *    "block_index = %x", block_index);
1032 		 */
1033 
1034 		switch (vpd_buf[block_index]) {
1035 		case 0x82:
1036 			index = block_index;
1037 			index += 1;
1038 			lenlo = vpd_buf[index];
1039 			index += 1;
1040 			lenhi = vpd_buf[index];
1041 			index += 1;
1042 			block_index = index;
1043 
1044 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1045 			block_index += block_size;
1046 
1047 			/*
1048 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1049 			 *    "block_size = %x", block_size);
1050 			 */
1051 
1052 			n = sizeof (buffer);
1053 			bzero(buffer, n);
1054 			bcopy(&vpd_buf[index], buffer,
1055 			    (block_size < (n - 1)) ? block_size : (n - 1));
1056 
1057 			(void) strncpy(vpd->id, buffer, (sizeof (vpd->id)-1));
1058 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "ID: %s",
1059 			    vpd->id);
1060 
1061 			break;
1062 
1063 		case 0x90:
1064 			index = block_index;
1065 			index += 1;
1066 			lenlo = vpd_buf[index];
1067 			index += 1;
1068 			lenhi = vpd_buf[index];
1069 			index += 1;
1070 			block_index = index;
1071 			sub_index = index;
1072 
1073 			block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1074 			block_index += block_size;
1075 
1076 			/*
1077 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1078 			 *    "block_size = %x", block_size);
1079 			 */
1080 
1081 			/* Scan for sub-blocks */
1082 			while ((sub_index < block_index) &&
1083 			    (sub_index < size)) {
1084 				/*
1085 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1086 				 *    "sub_index = %x", sub_index);
1087 				 */
1088 
1089 				index = sub_index;
1090 				tag[0] = vpd_buf[index++];
1091 				tag[1] = vpd_buf[index++];
1092 				tag[2] = 0;
1093 				sub_size = vpd_buf[index++];
1094 
1095 				/*
1096 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1097 				 *    "sub_size = %x", sub_size);
1098 				 */
1099 
1100 				sub_index = (index + sub_size);
1101 
1102 				n = sizeof (buffer);
1103 				bzero(buffer, n);
1104 				bcopy(&vpd_buf[index], buffer,
1105 				    (sub_size < (n - 1)) ? sub_size : (n - 1));
1106 
1107 				/*
1108 				 * Look for Engineering Change (EC)
1109 				 */
1110 				if (strcmp(tag, "EC") == 0) {
1111 					(void) strncpy(vpd->eng_change, buffer,
1112 					    (sizeof (vpd->eng_change)-1));
1113 					EMLXS_MSGF(EMLXS_CONTEXT,
1114 					    &emlxs_vpd_msg, "EC: %s",
1115 					    vpd->eng_change);
1116 				}
1117 				/*
1118 				 * Look for Manufacturer (MN)
1119 				 */
1120 				else if (strcmp(tag, "MN") == 0) {
1121 					(void) strncpy(vpd->manufacturer,
1122 					    buffer,
1123 					    (sizeof (vpd->manufacturer)-1));
1124 					EMLXS_MSGF(EMLXS_CONTEXT,
1125 					    &emlxs_vpd_msg, "MN: %s",
1126 					    vpd->manufacturer);
1127 				}
1128 				/*
1129 				 * Look for Serial Number (SN)
1130 				 */
1131 				else if (strcmp(tag, "SN") == 0) {
1132 					(void) strncpy(vpd->serial_num, buffer,
1133 					    (sizeof (vpd->serial_num)-1));
1134 					EMLXS_MSGF(EMLXS_CONTEXT,
1135 					    &emlxs_vpd_msg, "SN: %s",
1136 					    vpd->serial_num);
1137 
1138 					/* Validate the serial number */
1139 					if (strncmp(buffer, "FFFFFFFFFF", 10) ==
1140 					    0 ||
1141 					    strncmp(buffer, "0000000000", 10) ==
1142 					    0) {
1143 						vpd->serial_num[0] = 0;
1144 					}
1145 				}
1146 				/*
1147 				 * Look for Part Number (PN)
1148 				 */
1149 				else if (strcmp(tag, "PN") == 0) {
1150 					(void) strncpy(vpd->part_num, buffer,
1151 					    (sizeof (vpd->part_num)-1));
1152 					EMLXS_MSGF(EMLXS_CONTEXT,
1153 					    &emlxs_vpd_msg, "PN: %s",
1154 					    vpd->part_num);
1155 				}
1156 				/*
1157 				 * Look for (V0)
1158 				 */
1159 				else if (strcmp(tag, "V0") == 0) {
1160 					/* Not used */
1161 					EMLXS_MSGF(EMLXS_CONTEXT,
1162 					    &emlxs_vpd_msg, "V0: %s", buffer);
1163 				}
1164 				/*
1165 				 * Look for model description (V1)
1166 				 */
1167 				else if (strcmp(tag, "V1") == 0) {
1168 					(void) strncpy(vpd->model_desc, buffer,
1169 					    (sizeof (vpd->model_desc)-1));
1170 					EMLXS_MSGF(EMLXS_CONTEXT,
1171 					    &emlxs_vpd_msg, "Desc: %s",
1172 					    vpd->model_desc);
1173 				}
1174 				/*
1175 				 * Look for model (V2)
1176 				 */
1177 				else if (strcmp(tag, "V2") == 0) {
1178 					(void) strncpy(vpd->model, buffer,
1179 					    (sizeof (vpd->model)-1));
1180 					EMLXS_MSGF(EMLXS_CONTEXT,
1181 					    &emlxs_vpd_msg, "Model: %s",
1182 					    vpd->model);
1183 				}
1184 				/*
1185 				 * Look for program type (V3)
1186 				 */
1187 
1188 				else if (strcmp(tag, "V3") == 0) {
1189 					(void) strncpy(vpd->prog_types,
1190 					    buffer,
1191 					    (sizeof (vpd->prog_types)-1));
1192 					EMLXS_MSGF(EMLXS_CONTEXT,
1193 					    &emlxs_vpd_msg, "Prog Types: %s",
1194 					    vpd->prog_types);
1195 				}
1196 				/*
1197 				 * Look for port number (V4)
1198 				 */
1199 				else if (strcmp(tag, "V4") == 0) {
1200 					(void) strncpy(vpd->port_num, buffer,
1201 					    (sizeof (vpd->port_num)-1));
1202 					vpd->port_index =
1203 					    emlxs_strtol(vpd->port_num, 10);
1204 
1205 					EMLXS_MSGF(EMLXS_CONTEXT,
1206 					    &emlxs_vpd_msg, "Port: %s",
1207 					    (vpd->port_num[0]) ? vpd->
1208 					    port_num : "not applicable");
1209 				}
1210 				/*
1211 				 * Look for checksum (RV)
1212 				 */
1213 				else if (strcmp(tag, "RV") == 0) {
1214 					/* Not used */
1215 					EMLXS_MSGF(EMLXS_CONTEXT,
1216 					    &emlxs_vpd_msg, "Checksum: 0x%x",
1217 					    buffer[0]);
1218 				}
1219 
1220 				else {
1221 					/* Generic */
1222 					EMLXS_MSGF(EMLXS_CONTEXT,
1223 					    &emlxs_vpd_msg, "Tag: %s: %s",
1224 					    tag, buffer);
1225 				}
1226 			}
1227 
1228 			break;
1229 
1230 		case 0x78:
1231 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "End Tag.");
1232 			finished = 1;
1233 			break;
1234 
1235 		default:
1236 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1237 			    "Unknown block: %x %x %x %x %x %x %x %x",
1238 			    vpd_buf[index], vpd_buf[index + 1],
1239 			    vpd_buf[index + 2], vpd_buf[index + 3],
1240 			    vpd_buf[index + 4], vpd_buf[index + 5],
1241 			    vpd_buf[index + 6], vpd_buf[index + 7]);
1242 			return (0);
1243 		}
1244 	}
1245 
1246 	return (1);
1247 
1248 } /* emlxs_parse_vpd */
1249 
1250 
1251 /*
1252  * emlxs_parse_fcoe()
1253  *
1254  * This routine will parse the VPD data
1255  */
1256 extern int
1257 emlxs_parse_fcoe(emlxs_hba_t *hba, uint8_t *fcoep, uint32_t size)
1258 {
1259 	emlxs_port_t *port = &PPORT;
1260 	tlv_fcoe_t *fcoelist;
1261 	tlv_fcfconnectlist_t *fcflist;
1262 	int i;
1263 	uint32_t flags;
1264 	uint32_t entry_count;
1265 	char FabricName[32];
1266 	char SwitchName[32];
1267 
1268 	/* Validate the config region 23 signature */
1269 	if ((*fcoep != 'R') || (*(fcoep+1) != 'G') ||
1270 	    (*(fcoep+2) != '2') || (*(fcoep+3) != '3')) {
1271 		return (0);
1272 	}
1273 
1274 	/* Search the config region 23, for FCOE Parameters record */
1275 	i = 4;
1276 	while ((i < size) && (*(fcoep+i) != 0xA0) && (*(fcoep+i) != 0xff)) {
1277 		i += fcoep[i+1] * sizeof (uint32_t) + 2;
1278 	}
1279 
1280 	if (*(fcoep+i) == 0xA0) {
1281 		fcoelist = (tlv_fcoe_t *)(fcoep+i);
1282 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1283 		    "Found FCOE Params (A0):%d  x%x",
1284 		    fcoelist->length, fcoelist->fip_flags);
1285 		bcopy((uint8_t *)fcoelist, (uint8_t *)&hba->sli.sli4.cfgFCOE,
1286 		    sizeof (tlv_fcoe_t));
1287 	}
1288 
1289 
1290 	/* Search the config region 23, for FCF record */
1291 	i = 4;
1292 	while ((i < size) && (*(fcoep+i) != 0xA1) && (*(fcoep+i) != 0xff)) {
1293 		i += fcoep[i+1] * sizeof (uint32_t) + 2;
1294 	}
1295 
1296 	if (*(fcoep+i) == 0xA1) {
1297 		fcflist = (tlv_fcfconnectlist_t *)(fcoep+i);
1298 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1299 		    "Found FCF ConnectList (A1):%d", fcflist->length);
1300 
1301 		bcopy((uint8_t *)fcflist, (uint8_t *)&hba->sli.sli4.cfgFCF,
1302 		    sizeof (tlv_fcfconnectlist_t));
1303 
1304 		/* Display the list */
1305 		entry_count = (hba->sli.sli4.cfgFCF.length *
1306 		    sizeof (uint32_t)) / sizeof (tlv_fcfconnectentry_t);
1307 
1308 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1309 		    "FCF List: %d entries", entry_count);
1310 
1311 		for (i = 0; i < entry_count; i++) {
1312 			flags = *(uint32_t *)&hba->sli.sli4.cfgFCF.entry[i];
1313 			(void) emlxs_wwn_xlate(FabricName, sizeof (FabricName),
1314 			    hba->sli.sli4.cfgFCF.entry[i].FabricName);
1315 			(void) emlxs_wwn_xlate(SwitchName, sizeof (SwitchName),
1316 			    hba->sli.sli4.cfgFCF.entry[i].SwitchName);
1317 
1318 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1319 			    "FCF List:%02d %08x %s %s",
1320 			    i, flags, FabricName, SwitchName);
1321 		}
1322 	}
1323 
1324 	return (1);
1325 
1326 } /* emlxs_parse_fcoe */
1327 
1328 
1329 extern void
1330 emlxs_decode_firmware_rev(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1331 {
1332 	if (vpd->rBit) {
1333 		switch (hba->sli_mode) {
1334 		case EMLXS_HBA_SLI4_MODE:
1335 			(void) strncpy(vpd->fw_version, vpd->sli4FwName,
1336 			    (sizeof (vpd->fw_version)-1));
1337 			(void) strncpy(vpd->fw_label, vpd->sli4FwLabel,
1338 			    (sizeof (vpd->fw_label)-1));
1339 			break;
1340 		case EMLXS_HBA_SLI3_MODE:
1341 			(void) strncpy(vpd->fw_version, vpd->sli3FwName,
1342 			    (sizeof (vpd->fw_version)-1));
1343 			(void) strncpy(vpd->fw_label, vpd->sli3FwLabel,
1344 			    (sizeof (vpd->fw_label)-1));
1345 			break;
1346 		case EMLXS_HBA_SLI2_MODE:
1347 			(void) strncpy(vpd->fw_version, vpd->sli2FwName,
1348 			    (sizeof (vpd->fw_version)-1));
1349 			(void) strncpy(vpd->fw_label, vpd->sli2FwLabel,
1350 			    (sizeof (vpd->fw_label)-1));
1351 			break;
1352 		case EMLXS_HBA_SLI1_MODE:
1353 			(void) strncpy(vpd->fw_version, vpd->sli1FwName,
1354 			    (sizeof (vpd->fw_version)-1));
1355 			(void) strncpy(vpd->fw_label, vpd->sli1FwLabel,
1356 			    (sizeof (vpd->fw_label)-1));
1357 			break;
1358 		default:
1359 			(void) strncpy(vpd->fw_version, "unknown",
1360 			    (sizeof (vpd->fw_version)-1));
1361 			(void) strncpy(vpd->fw_label, vpd->fw_version,
1362 			    (sizeof (vpd->fw_label)-1));
1363 		}
1364 	} else {
1365 		emlxs_decode_version(vpd->smFwRev, vpd->fw_version,
1366 		    sizeof (vpd->fw_version));
1367 		(void) strncpy(vpd->fw_label, vpd->fw_version,
1368 		    (sizeof (vpd->fw_label)-1));
1369 	}
1370 
1371 	return;
1372 
1373 } /* emlxs_decode_firmware_rev() */
1374 
1375 
1376 
1377 extern void
1378 emlxs_decode_version(uint32_t version, char *buffer, size_t len)
1379 {
1380 	uint32_t b1, b2, b3, b4;
1381 	char c;
1382 
1383 	b1 = (version & 0x0000f000) >> 12;
1384 	b2 = (version & 0x00000f00) >> 8;
1385 	b3 = (version & 0x000000c0) >> 6;
1386 	b4 = (version & 0x00000030) >> 4;
1387 
1388 	if (b1 == 0 && b2 == 0) {
1389 		(void) snprintf(buffer, len, "none");
1390 		return;
1391 	}
1392 
1393 	c = 0;
1394 	switch (b4) {
1395 	case 0:
1396 		c = 'n';
1397 		break;
1398 	case 1:
1399 		c = 'a';
1400 		break;
1401 	case 2:
1402 		c = 'b';
1403 		break;
1404 	case 3:
1405 		if ((version & 0x0000000f)) {
1406 			c = 'x';
1407 		}
1408 		break;
1409 
1410 	}
1411 	b4 = (version & 0x0000000f);
1412 
1413 	if (c == 0) {
1414 		(void) snprintf(buffer, len, "%d.%d%d", b1, b2, b3);
1415 	} else {
1416 		(void) snprintf(buffer, len, "%d.%d%d%c%d", b1, b2, b3, c, b4);
1417 	}
1418 
1419 	return;
1420 
1421 } /* emlxs_decode_version() */
1422 
1423 
1424 extern void
1425 emlxs_decode_label(char *label, char *buffer, int bige, size_t len)
1426 {
1427 	uint32_t i;
1428 	char name[16];
1429 
1430 	bzero(name, sizeof (name));
1431 	bcopy(label, name, MIN(sizeof (name), len));
1432 	/* bige is TRUE if the data format is big endian */
1433 
1434 	if (bige) {
1435 		/* Data format big Endian */
1436 		LE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
1437 
1438 		for (i = 0; i < sizeof (name); i++) {
1439 			if (name[i] == 0x20) {
1440 				name[i] = 0;
1441 			}
1442 		}
1443 	} else {
1444 		/* Data format little Endian */
1445 		BE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
1446 
1447 		for (i = 0; i < sizeof (name); i++) {
1448 			if (name[i] == 0x20) {
1449 				name[i] = 0;
1450 			}
1451 		}
1452 	}
1453 
1454 	(void) strlcpy(buffer, name, len);
1455 
1456 	return;
1457 
1458 } /* emlxs_decode_label() */
1459 
1460 
1461 extern uint32_t
1462 emlxs_strtol(char *str, uint32_t base)
1463 {
1464 	uint32_t value = 0;
1465 	char *ptr;
1466 	uint32_t factor = 1;
1467 	uint32_t digits;
1468 
1469 	if (*str == 0) {
1470 		return (0);
1471 	}
1472 
1473 	if (base != 10 && base != 16) {
1474 		return (0);
1475 	}
1476 
1477 	/* Get max digits of value */
1478 	digits = (base == 10) ? 9 : 8;
1479 
1480 	/* Position pointer to end of string */
1481 	ptr = str + strlen(str);
1482 
1483 	/* Process string backwards */
1484 	while ((ptr-- > str) && digits) {
1485 		/* check for base 10 numbers */
1486 		if (*ptr >= '0' && *ptr <= '9') {
1487 			value += ((uint32_t)(*ptr - '0')) * factor;
1488 			factor *= base;
1489 			digits--;
1490 		} else if (base == 16) {
1491 			/* Check for base 16 numbers */
1492 			if (*ptr >= 'a' && *ptr <= 'f') {
1493 				value +=
1494 				    ((uint32_t)(*ptr - 'a') + 10) * factor;
1495 				factor *= base;
1496 				digits--;
1497 			} else if (*ptr >= 'A' && *ptr <= 'F') {
1498 				value +=
1499 				    ((uint32_t)(*ptr - 'A') + 10) * factor;
1500 				factor *= base;
1501 				digits--;
1502 			} else if (factor > 1) {
1503 				break;
1504 			}
1505 		} else if (factor > 1) {
1506 			break;
1507 		}
1508 	}
1509 
1510 	return (value);
1511 
1512 } /* emlxs_strtol() */
1513 
1514 
1515 extern uint64_t
1516 emlxs_strtoll(char *str, uint32_t base)
1517 {
1518 	uint64_t value = 0;
1519 	char *ptr;
1520 	uint32_t factor = 1;
1521 	uint32_t digits;
1522 
1523 	if (*str == 0) {
1524 		return (0);
1525 	}
1526 
1527 	if (base != 10 && base != 16) {
1528 		return (0);
1529 	}
1530 
1531 	/* Get max digits of value */
1532 	digits = (base == 10) ? 19 : 16;
1533 
1534 	/* Position pointer to end of string */
1535 	ptr = str + strlen(str);
1536 
1537 	/* Process string backwards */
1538 	while ((ptr-- > str) && digits) {
1539 		/* check for base 10 numbers */
1540 		if (*ptr >= '0' && *ptr <= '9') {
1541 			value += ((uint32_t)(*ptr - '0')) * factor;
1542 			factor *= base;
1543 			digits--;
1544 		} else if (base == 16) {
1545 			/* Check for base 16 numbers */
1546 			if (*ptr >= 'a' && *ptr <= 'f') {
1547 				value +=
1548 				    ((uint32_t)(*ptr - 'a') + 10) * factor;
1549 				factor *= base;
1550 				digits--;
1551 			} else if (*ptr >= 'A' && *ptr <= 'F') {
1552 				value +=
1553 				    ((uint32_t)(*ptr - 'A') + 10) * factor;
1554 				factor *= base;
1555 				digits--;
1556 			} else if (factor > 1) {
1557 				break;
1558 			}
1559 		} else if (factor > 1) {
1560 			break;
1561 		}
1562 	}
1563 
1564 	return (value);
1565 
1566 } /* emlxs_strtoll() */
1567 
1568 extern void
1569 emlxs_parse_prog_types(emlxs_hba_t *hba, char *prog_types)
1570 {
1571 	emlxs_port_t *port = &PPORT;
1572 	uint32_t i;
1573 	char *ptr;
1574 	emlxs_model_t *model;
1575 	char types_buffer[256];
1576 	char *types;
1577 
1578 	bcopy(prog_types, types_buffer, 256);
1579 	types = types_buffer;
1580 
1581 	model = &hba->model_info;
1582 
1583 	while (*types) {
1584 		if (strncmp(types, "T2:", 3) == 0) {
1585 			bzero(model->pt_2, sizeof (model->pt_2));
1586 			types += 3;
1587 
1588 			i = 0;
1589 			while (*types && *types != 'T') {
1590 				/* Null terminate the next value */
1591 				ptr = types;
1592 				while (*ptr && (*ptr != ','))
1593 					ptr++;
1594 				*ptr = 0;
1595 
1596 				/* Save the value */
1597 				model->pt_2[i++] =
1598 				    (uint8_t)emlxs_strtol(types, 16);
1599 
1600 				/*
1601 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1602 				 * "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
1603 				 */
1604 
1605 				/* Move the str pointer */
1606 				types = ptr + 1;
1607 			}
1608 
1609 		} else if (strncmp(types, "T3:", 3) == 0) {
1610 			bzero(model->pt_3, sizeof (model->pt_3));
1611 			types += 3;
1612 
1613 			i = 0;
1614 			while (*types && *types != 'T') {
1615 				/* Null terminate the next value */
1616 				ptr = types;
1617 				while (*ptr && (*ptr != ','))
1618 					ptr++;
1619 				*ptr = 0;
1620 
1621 				/* Save the value */
1622 				model->pt_3[i++] =
1623 				    (uint8_t)emlxs_strtol(types, 16);
1624 
1625 				/*
1626 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1627 				 * "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
1628 				 */
1629 
1630 				/* Move the str pointer */
1631 				types = ptr + 1;
1632 			}
1633 		} else if (strncmp(types, "T6:", 3) == 0) {
1634 			bzero(model->pt_6, sizeof (model->pt_6));
1635 			types += 3;
1636 
1637 			i = 0;
1638 			while (*types && *types != 'T') {
1639 				/* Null terminate the next value */
1640 				ptr = types;
1641 				while (*ptr && (*ptr != ','))
1642 					ptr++;
1643 				*ptr = 0;
1644 
1645 				/* Save the value */
1646 				model->pt_6[i++] =
1647 				    (uint8_t)emlxs_strtol(types, 16);
1648 				model->pt_6[i] = 0;
1649 
1650 				/*
1651 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1652 				 * "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
1653 				 */
1654 
1655 				/* Move the str pointer */
1656 				types = ptr + 1;
1657 			}
1658 		} else if (strncmp(types, "T7:", 3) == 0) {
1659 			bzero(model->pt_7, sizeof (model->pt_7));
1660 			types += 3;
1661 
1662 			i = 0;
1663 			while (*types && *types != 'T') {
1664 				/* Null terminate the next value */
1665 				ptr = types;
1666 				while (*ptr && (*ptr != ','))
1667 					ptr++;
1668 				*ptr = 0;
1669 
1670 				/* Save the value */
1671 				model->pt_7[i++] =
1672 				    (uint8_t)emlxs_strtol(types, 16);
1673 				model->pt_7[i] = 0;
1674 
1675 				/*
1676 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1677 				 * "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
1678 				 */
1679 
1680 				/* Move the str pointer */
1681 				types = ptr + 1;
1682 			}
1683 		} else if (strncmp(types, "TA:", 3) == 0) {
1684 			bzero(model->pt_A, sizeof (model->pt_A));
1685 			types += 3;
1686 
1687 			i = 0;
1688 			while (*types && *types != 'T') {
1689 				/* Null terminate the next value */
1690 				ptr = types;
1691 				while (*ptr && (*ptr != ','))
1692 					ptr++;
1693 				*ptr = 0;
1694 
1695 				/* Save the value */
1696 				model->pt_A[i++] =
1697 				    (uint8_t)emlxs_strtol(types, 16);
1698 
1699 				/*
1700 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1701 				 * "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
1702 				 */
1703 
1704 				/* Move the str pointer */
1705 				types = ptr + 1;
1706 			}
1707 		} else if (strncmp(types, "TB:", 3) == 0) {
1708 			bzero(model->pt_B, sizeof (model->pt_B));
1709 			types += 3;
1710 
1711 			i = 0;
1712 			while (*types && *types != 'T') {
1713 				/* Null terminate the next value */
1714 				ptr = types;
1715 				while (*ptr && (*ptr != ','))
1716 					ptr++;
1717 				*ptr = 0;
1718 
1719 				/* Save the value */
1720 				model->pt_B[i++] =
1721 				    (uint8_t)emlxs_strtol(types, 16);
1722 
1723 				/*
1724 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1725 				 * "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
1726 				 */
1727 
1728 				/* Move the str pointer */
1729 				types = ptr + 1;
1730 			}
1731 		} else if (strncmp(types, "TFF:", 4) == 0) {
1732 			bzero(model->pt_FF, sizeof (model->pt_FF));
1733 			types += 4;
1734 
1735 			i = 0;
1736 			while (*types && *types != 'T') {
1737 				/* Null terminate the next value */
1738 				ptr = types;
1739 				while (*ptr && (*ptr != ','))
1740 					ptr++;
1741 				*ptr = 0;
1742 
1743 				/* Save the value */
1744 				model->pt_FF[i++] =
1745 				    (uint8_t)emlxs_strtol(types, 16);
1746 
1747 				/*
1748 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1749 				 * "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
1750 				 */
1751 
1752 				/* Move the str pointer */
1753 				types = ptr + 1;
1754 			}
1755 		} else if (strncmp(types, "T20:", 4) == 0) {
1756 			bzero(model->pt_20, sizeof (model->pt_20));
1757 			types += 4;
1758 
1759 			i = 0;
1760 			while (*types && *types != 'T') {
1761 				/* Null terminate the next value */
1762 				ptr = types;
1763 				while (*ptr && (*ptr != ','))
1764 					ptr++;
1765 				*ptr = 0;
1766 
1767 				/* Save the value */
1768 				model->pt_20[i++] =
1769 				    (uint8_t)emlxs_strtol(types, 16);
1770 				model->pt_20[i] = 0;
1771 
1772 				/*
1773 				 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1774 				 * "T20[%d]: 0x%x", i-1, model->pt_20[i-1]);
1775 				 */
1776 
1777 				/* Move the str pointer */
1778 				types = ptr + 1;
1779 			}
1780 		} else {
1781 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1782 			    "Unknown prog type string = %s", types);
1783 			break;
1784 		}
1785 	}
1786 
1787 	return;
1788 
1789 } /* emlxs_parse_prog_types() */
1790 
1791 
1792 extern void
1793 emlxs_build_prog_types(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1794 {
1795 	uint32_t i;
1796 	uint32_t found = 0;
1797 	char buffer[256];
1798 
1799 	bzero(vpd->prog_types, sizeof (vpd->prog_types));
1800 
1801 	/* Rebuild the prog type string */
1802 	if (hba->model_info.pt_2[0]) {
1803 		(void) strlcat(vpd->prog_types, "T2:",
1804 		    sizeof (vpd->prog_types));
1805 		found = 1;
1806 
1807 		i = 0;
1808 		while ((i < 8) && (hba->model_info.pt_2[i])) {
1809 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1810 			    hba->model_info.pt_2[i]);
1811 			(void) strlcat(vpd->prog_types, buffer,
1812 			    sizeof (vpd->prog_types));
1813 			i++;
1814 		}
1815 	}
1816 
1817 	if (hba->model_info.pt_3[0]) {
1818 		(void) strlcat(vpd->prog_types, "T3:",
1819 		    sizeof (vpd->prog_types));
1820 		found = 1;
1821 
1822 		i = 0;
1823 		while ((i < 8) && (hba->model_info.pt_3[i])) {
1824 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1825 			    hba->model_info.pt_3[i]);
1826 			(void) strlcat(vpd->prog_types, buffer,
1827 			    sizeof (vpd->prog_types));
1828 			i++;
1829 
1830 		}
1831 	}
1832 
1833 	if (hba->model_info.pt_6[0]) {
1834 		(void) strlcat(vpd->prog_types, "T6:",
1835 		    sizeof (vpd->prog_types));
1836 		found = 1;
1837 
1838 		i = 0;
1839 		while ((i < 8) && (hba->model_info.pt_6[i])) {
1840 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1841 			    hba->model_info.pt_6[i]);
1842 			(void) strlcat(vpd->prog_types, buffer,
1843 			    sizeof (vpd->prog_types));
1844 			i++;
1845 		}
1846 	}
1847 
1848 	if (hba->model_info.pt_7[0]) {
1849 		(void) strlcat(vpd->prog_types, "T7:",
1850 		    sizeof (vpd->prog_types));
1851 		found = 1;
1852 
1853 		i = 0;
1854 		while ((i < 8) && (hba->model_info.pt_7[i])) {
1855 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1856 			    hba->model_info.pt_7[i]);
1857 			(void) strlcat(vpd->prog_types, buffer,
1858 			    sizeof (vpd->prog_types));
1859 			i++;
1860 		}
1861 	}
1862 
1863 	if (hba->model_info.pt_A[0]) {
1864 		(void) strlcat(vpd->prog_types, "TA:",
1865 		    sizeof (vpd->prog_types));
1866 		found = 1;
1867 
1868 		i = 0;
1869 		while ((i < 8) && (hba->model_info.pt_A[i])) {
1870 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1871 			    hba->model_info.pt_A[i]);
1872 			(void) strlcat(vpd->prog_types, buffer,
1873 			    sizeof (vpd->prog_types));
1874 			i++;
1875 		}
1876 	}
1877 
1878 
1879 	if (hba->model_info.pt_B[0]) {
1880 		(void) strlcat(vpd->prog_types, "TB:",
1881 		    sizeof (vpd->prog_types));
1882 		found = 1;
1883 
1884 		i = 0;
1885 		while ((i < 8) && (hba->model_info.pt_B[i])) {
1886 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1887 			    hba->model_info.pt_B[i]);
1888 			(void) strlcat(vpd->prog_types, buffer,
1889 			    sizeof (vpd->prog_types));
1890 			i++;
1891 		}
1892 	}
1893 
1894 	if (hba->model_info.pt_20[0]) {
1895 		(void) strlcat(vpd->prog_types, "T20:",
1896 		    sizeof (vpd->prog_types));
1897 		found = 1;
1898 
1899 		i = 0;
1900 		while ((i < 8) && (hba->model_info.pt_20[i])) {
1901 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1902 			    hba->model_info.pt_20[i]);
1903 			(void) strlcat(vpd->prog_types, buffer,
1904 			    sizeof (vpd->prog_types));
1905 			i++;
1906 		}
1907 	}
1908 
1909 	if (hba->model_info.pt_FF[0]) {
1910 		(void) strlcat(vpd->prog_types, "TFF:",
1911 		    sizeof (vpd->prog_types));
1912 		found = 1;
1913 
1914 		i = 0;
1915 		while ((i < 8) && (hba->model_info.pt_FF[i])) {
1916 			(void) snprintf(buffer, sizeof (buffer), "%X,",
1917 			    hba->model_info.pt_FF[i]);
1918 			(void) strlcat(vpd->prog_types, buffer,
1919 			    sizeof (vpd->prog_types));
1920 			i++;
1921 		}
1922 	}
1923 
1924 	if (found) {
1925 		/* Terminate at the last comma in string */
1926 		vpd->prog_types[(strlen(vpd->prog_types) - 1)] = 0;
1927 	}
1928 
1929 	return;
1930 
1931 } /* emlxs_build_prog_types() */
1932 
1933 
1934 extern uint32_t
1935 emlxs_init_adapter_info(emlxs_hba_t *hba)
1936 {
1937 	emlxs_port_t *port = &PPORT;
1938 	uint32_t pci_id;
1939 	uint32_t cache_line;
1940 	uint32_t channels;
1941 	uint16_t device_id;
1942 	uint16_t ssdid;
1943 	uint32_t i;
1944 	uint32_t found = 0;
1945 	int32_t *prop;
1946 	uint32_t num_prop;
1947 
1948 	if (hba->bus_type == SBUS_FC) {
1949 		if (hba->pci_acc_handle == NULL) {
1950 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
1951 			    sizeof (emlxs_model_t));
1952 
1953 			hba->model_info.device_id = 0;
1954 
1955 			return (0);
1956 		}
1957 
1958 		/* Read the PCI device id */
1959 		pci_id =
1960 		    ddi_get32(hba->pci_acc_handle,
1961 		    (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
1962 		device_id = (uint16_t)(pci_id >> 16);
1963 
1964 		/* Find matching adapter model */
1965 		for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
1966 			if (emlxs_sbus_model[i].device_id == device_id) {
1967 				bcopy(&emlxs_sbus_model[i], &hba->model_info,
1968 				    sizeof (emlxs_model_t));
1969 				found = 1;
1970 				break;
1971 			}
1972 		}
1973 
1974 		/* If not found then use the unknown model */
1975 		if (!found) {
1976 			bcopy(&emlxs_sbus_model[0], &hba->model_info,
1977 			    sizeof (emlxs_model_t));
1978 
1979 			hba->model_info.device_id = device_id;
1980 
1981 			return (0);
1982 		}
1983 	} else {	/* PCI model */
1984 
1985 		if (hba->pci_acc_handle == NULL) {
1986 			bcopy(&emlxs_pci_model[0], &hba->model_info,
1987 			    sizeof (emlxs_model_t));
1988 
1989 			hba->model_info.device_id = 0;
1990 
1991 			return (0);
1992 		}
1993 
1994 		/* Read the PCI device id */
1995 		device_id =
1996 		    ddi_get16(hba->pci_acc_handle,
1997 		    (uint16_t *)(hba->pci_addr + PCI_DEVICE_ID_REGISTER));
1998 
1999 		/* Read the PCI Subsystem id */
2000 		ssdid =
2001 		    ddi_get16(hba->pci_acc_handle,
2002 		    (uint16_t *)(hba->pci_addr + PCI_SSDID_REGISTER));
2003 
2004 		if (ssdid == 0 || ssdid == 0xffff) {
2005 			ssdid = device_id;
2006 		}
2007 
2008 		/* Read the Cache Line reg */
2009 		cache_line =
2010 		    ddi_get32(hba->pci_acc_handle,
2011 		    (uint32_t *)(hba->pci_addr + PCI_CACHE_LINE_REGISTER));
2012 
2013 		/* Check for the multifunction bit being set */
2014 		if ((cache_line & 0x00ff0000) == 0x00800000) {
2015 			channels = EMLXS_MULTI_CHANNEL;
2016 		} else {
2017 			channels = EMLXS_SINGLE_CHANNEL;
2018 		}
2019 
2020 		/* If device ids are unique, then use them for search */
2021 		if (device_id != ssdid) {
2022 			/*
2023 			 * Find matching adapter model using
2024 			 * device_id, ssdid, and channels
2025 			 */
2026 			for (i = 1; i < emlxs_pci_model_count; i++) {
2027 				if (emlxs_pci_model[i].device_id ==
2028 				    device_id &&
2029 				    emlxs_pci_model[i].ssdid == ssdid &&
2030 				    emlxs_pci_model[i].channels ==
2031 				    channels) {
2032 					bcopy(&emlxs_pci_model[i],
2033 					    &hba->model_info,
2034 					    sizeof (emlxs_model_t));
2035 					found = 1;
2036 					break;
2037 				}
2038 			}
2039 		}
2040 
2041 		/* If adapter not found, try again */
2042 		if (!found) {
2043 			/*
2044 			 * Find matching adapter model using
2045 			 * device_id and channels
2046 			 */
2047 			for (i = 1; i < emlxs_pci_model_count; i++) {
2048 				if (emlxs_pci_model[i].device_id == device_id &&
2049 				    emlxs_pci_model[i].channels == channels) {
2050 					bcopy(&emlxs_pci_model[i],
2051 					    &hba->model_info,
2052 					    sizeof (emlxs_model_t));
2053 					found = 1;
2054 					break;
2055 				}
2056 			}
2057 		}
2058 
2059 		/* If adapter not found, try one last time */
2060 		if (!found) {
2061 			/*
2062 			 * Find matching adapter model using
2063 			 * device_id only
2064 			 */
2065 			for (i = 1; i < emlxs_pci_model_count; i++) {
2066 				if (emlxs_pci_model[i].device_id == device_id) {
2067 					bcopy(&emlxs_pci_model[i],
2068 					    &hba->model_info,
2069 					    sizeof (emlxs_model_t));
2070 					found = 1;
2071 					break;
2072 				}
2073 			}
2074 		}
2075 
2076 		/* If not found, set adapter to unknown */
2077 		if (!found) {
2078 			bcopy(&emlxs_pci_model[0], &hba->model_info,
2079 			    sizeof (emlxs_model_t));
2080 
2081 			hba->model_info.device_id = device_id;
2082 			hba->model_info.ssdid = ssdid;
2083 
2084 			return (0);
2085 		}
2086 
2087 #ifndef SATURN_MSI_SUPPORT
2088 		/*
2089 		 * This will disable MSI support for Saturn adapter's
2090 		 * due to a PCI bus issue
2091 		 */
2092 		if (hba->model_info.chip == EMLXS_SATURN_CHIP) {
2093 			hba->model_info.flags &=
2094 			    ~(EMLXS_MSI_SUPPORTED | EMLXS_MSIX_SUPPORTED);
2095 		}
2096 #endif /* !SATURN_MSI_SUPPORT */
2097 
2098 		/* Scan the PCI capabilities */
2099 		emlxs_pci_cap_offsets(hba);
2100 
2101 #ifdef MSI_SUPPORT
2102 		/* Verify MSI support */
2103 		if ((hba->model_info.flags & EMLXS_MSI_SUPPORTED) &&
2104 		    !hba->pci_cap_offset[PCI_CAP_ID_MSI]) {
2105 			hba->model_info.flags &= ~EMLXS_MSI_SUPPORTED;
2106 		}
2107 
2108 		/* Verify MSI-X support */
2109 		if ((hba->model_info.flags & EMLXS_MSIX_SUPPORTED) &&
2110 		    !hba->pci_cap_offset[PCI_CAP_ID_MSI_X]) {
2111 			hba->model_info.flags &= ~EMLXS_MSIX_SUPPORTED;
2112 		}
2113 #endif /* MSI_SUPPORT */
2114 
2115 		/* Set the sli_intf value */
2116 		if (hba->pci_cap_offset[PCI_CAP_ID_VS]) {
2117 			/* Save the SLI_INTF register, this contains */
2118 			/* information about the BAR register layout */
2119 			/* and other HBA information. */
2120 			hba->sli_intf =
2121 			    ddi_get32(hba->pci_acc_handle,
2122 			    (uint32_t *)(hba->pci_addr +
2123 			    hba->pci_cap_offset[PCI_CAP_ID_VS] +
2124 			    PCI_VS_SLI_INTF_OFFSET));
2125 
2126 			EMLXS_MSGF(EMLXS_CONTEXT,
2127 			    &emlxs_init_debug_msg, "PCI_CAP_ID_VS: "
2128 			    "SLI_INTF:%08x",
2129 			    hba->sli_intf);
2130 
2131 			/* Check validity */
2132 			if ((hba->sli_intf & SLI_INTF_VALID_MASK) !=
2133 			    SLI_INTF_VALID) {
2134 				hba->sli_intf = 0;
2135 			}
2136 		}
2137 	}
2138 
2139 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba->dip, 0,
2140 	    "reg", &prop, &num_prop) == DDI_PROP_SUCCESS) {
2141 		/* Parse the property for PCI function, device and bus no. */
2142 		hba->pci_function_number =
2143 		    (uint8_t)((prop[0] & 0x00000700) >> 8);
2144 		hba->pci_device_number =
2145 		    (uint8_t)((prop[0] & 0x0000f800) >> 11);
2146 		hba->pci_bus_number = (uint8_t)((prop[0] & 0x00ff0000) >> 16);
2147 		ddi_prop_free((void *)prop);
2148 	}
2149 
2150 	switch (hba->sli_intf & SLI_INTF_SLI_REV_MASK) {
2151 	case SLI_INTF_SLI_REV_NONE: /* Legacy support */
2152 		if (hba->model_info.sli_mask & EMLXS_SLI4_MASK) {
2153 			hba->sli_api = emlxs_sli4_api;
2154 		} else {
2155 			hba->sli_api = emlxs_sli3_api;
2156 		}
2157 		break;
2158 
2159 	case SLI_INTF_SLI_REV_3:
2160 		if (!(hba->model_info.sli_mask & EMLXS_SLI3_MASK)) {
2161 			EMLXS_MSGF(EMLXS_CONTEXT,
2162 			    &emlxs_init_failed_msg,
2163 			    "Adapter does not support SLI3 interface. "
2164 			    "sli_intf=%08x sli_mask=%08x",
2165 			    hba->sli_intf, hba->model_info.sli_mask);
2166 			return (0);
2167 		}
2168 		hba->sli_api = emlxs_sli3_api;
2169 		break;
2170 
2171 	case SLI_INTF_SLI_REV_4:
2172 		if (!(hba->model_info.sli_mask & EMLXS_SLI4_MASK)) {
2173 			EMLXS_MSGF(EMLXS_CONTEXT,
2174 			    &emlxs_init_failed_msg,
2175 			    "Adapter does not support SLI4 interface. "
2176 			    "sli_intf=%08x sli_mask=%08x",
2177 			    hba->sli_intf, hba->model_info.sli_mask);
2178 			return (0);
2179 		}
2180 		hba->sli_api = emlxs_sli4_api;
2181 		break;
2182 
2183 	default:
2184 		EMLXS_MSGF(EMLXS_CONTEXT,
2185 		    &emlxs_init_failed_msg,
2186 		    "Invalid SLI interface specified. "
2187 		    "sli_intf=%08x sli_mask=%08x",
2188 		    hba->sli_intf, hba->model_info.sli_mask);
2189 		return (0);
2190 	}
2191 
2192 #ifdef FMA_SUPPORT
2193 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
2194 	    != DDI_FM_OK) {
2195 		EMLXS_MSGF(EMLXS_CONTEXT,
2196 		    &emlxs_invalid_access_handle_msg, NULL);
2197 		return (0);
2198 	}
2199 #endif  /* FMA_SUPPORT */
2200 
2201 	return (1);
2202 
2203 } /* emlxs_init_adapter_info()  */
2204 
2205 
2206 /* ARGSUSED */
2207 static void
2208 emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2209 {
2210 	emlxs_port_t *port = &PPORT;
2211 	IOCB *iocb;
2212 	uint32_t *w;
2213 	int i, j;
2214 
2215 	iocb = &iocbq->iocb;
2216 
2217 	if (iocb->ULPSTATUS != 0) {
2218 		return;
2219 	}
2220 
2221 	switch (iocb->un.astat.EventCode) {
2222 	case 0x0100:	/* Temp Warning */
2223 
2224 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_warning_msg,
2225 		    "Adapter is very hot (%d �C). Take corrective action.",
2226 		    iocb->ULPCONTEXT);
2227 
2228 		hba->temperature = iocb->ULPCONTEXT;
2229 		emlxs_log_temp_event(port, 0x02, iocb->ULPCONTEXT);
2230 
2231 
2232 		break;
2233 
2234 
2235 	case 0x0101:	/* Temp Safe */
2236 
2237 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_msg,
2238 		    "Adapter temperature now safe (%d �C).",
2239 		    iocb->ULPCONTEXT);
2240 
2241 		hba->temperature = iocb->ULPCONTEXT;
2242 		emlxs_log_temp_event(port, 0x03, iocb->ULPCONTEXT);
2243 
2244 		break;
2245 
2246 	default:
2247 
2248 		w = (uint32_t *)iocb;
2249 		for (i = 0, j = 0; i < 8; i++, j += 2) {
2250 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_async_msg,
2251 			    "(Word[%d]=%x Word[%d]=%x)", j, w[j], j + 1,
2252 			    w[j + 1]);
2253 		}
2254 
2255 		emlxs_log_async_event(port, iocb);
2256 	}
2257 
2258 	return;
2259 
2260 } /* emlxs_handle_async_event() */
2261 
2262 
2263 /* ARGSUSED */
2264 extern void
2265 emlxs_reset_link_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2266 {
2267 	emlxs_port_t *port = &PPORT;
2268 
2269 	/* Attempt a link reset to recover */
2270 	(void) emlxs_reset(port, FC_FCA_LINK_RESET);
2271 
2272 	return;
2273 
2274 } /* emlxs_reset_link_thread() */
2275 
2276 
2277 /* ARGSUSED */
2278 extern void
2279 emlxs_restart_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2280 {
2281 	emlxs_port_t *port = &PPORT;
2282 
2283 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Restarting...");
2284 
2285 	/* Attempt a full hardware reset to recover */
2286 	if (emlxs_reset(port, FC_FCA_RESET) != FC_SUCCESS) {
2287 		EMLXS_STATE_CHANGE(hba, FC_ERROR);
2288 
2289 		emlxs_shutdown_thread(hba, arg1, arg2);
2290 	}
2291 
2292 	return;
2293 
2294 } /* emlxs_restart_thread() */
2295 
2296 
2297 /* ARGSUSED */
2298 extern void
2299 emlxs_shutdown_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2300 {
2301 	emlxs_port_t *port = &PPORT;
2302 
2303 	mutex_enter(&EMLXS_PORT_LOCK);
2304 	if (hba->flag & FC_SHUTDOWN) {
2305 		mutex_exit(&EMLXS_PORT_LOCK);
2306 		return;
2307 	}
2308 	hba->flag |= FC_SHUTDOWN;
2309 	mutex_exit(&EMLXS_PORT_LOCK);
2310 
2311 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
2312 	    "Shutting down...");
2313 
2314 	/* Take adapter offline and leave it there */
2315 	(void) emlxs_offline(hba, 0);
2316 
2317 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2318 		/*
2319 		 * Dump is not defined for SLI4, so just
2320 		 * reset the HBA for now.
2321 		 */
2322 		EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
2323 
2324 	} else {
2325 		if (hba->flag & FC_OVERTEMP_EVENT) {
2326 			emlxs_log_temp_event(port, 0x01,
2327 			    hba->temperature);
2328 		} else {
2329 			emlxs_log_dump_event(port, NULL, 0);
2330 		}
2331 	}
2332 
2333 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_shutdown_msg, "Reboot required.");
2334 
2335 	return;
2336 
2337 } /* emlxs_shutdown_thread() */
2338 
2339 
2340 /* ARGSUSED */
2341 extern void
2342 emlxs_proc_channel(emlxs_hba_t *hba, CHANNEL *cp, void *arg2)
2343 {
2344 	IOCBQ *iocbq;
2345 	IOCBQ *rsp_head;
2346 
2347 	/*
2348 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
2349 	 * "proc_channel: channel=%d", cp->channelno);
2350 	 */
2351 
2352 	mutex_enter(&cp->rsp_lock);
2353 
2354 	while ((rsp_head = cp->rsp_head) != NULL) {
2355 		cp->rsp_head = NULL;
2356 		cp->rsp_tail = NULL;
2357 
2358 		mutex_exit(&cp->rsp_lock);
2359 
2360 		while ((iocbq = rsp_head) != NULL) {
2361 			rsp_head = (IOCBQ *) iocbq->next;
2362 
2363 			emlxs_proc_channel_event(hba, cp, iocbq);
2364 		}
2365 
2366 		mutex_enter(&cp->rsp_lock);
2367 	}
2368 
2369 	mutex_exit(&cp->rsp_lock);
2370 
2371 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0);
2372 
2373 	return;
2374 
2375 } /* emlxs_proc_channel() */
2376 
2377 
2378 /*
2379  * Called from SLI ring event routines to process a rsp ring IOCB.
2380  */
2381 void
2382 emlxs_proc_channel_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2383 {
2384 	emlxs_port_t *port = &PPORT;
2385 	char buffer[MAX_MSG_DATA + 1];
2386 	IOCB *iocb;
2387 	emlxs_buf_t *sbp;
2388 	fc_packet_t *pkt;
2389 
2390 	iocb = &iocbq->iocb;
2391 
2392 #ifdef DEBUG_CMPL_IOCB
2393 	emlxs_data_dump(port, "CMPL_IOCB", (uint32_t *)iocb, 8, 0);
2394 #endif
2395 
2396 	sbp = (emlxs_buf_t *)iocbq->sbp;
2397 	if (sbp) {
2398 		if (!(sbp->pkt_flags & PACKET_VALID) ||
2399 		    (sbp->pkt_flags & (PACKET_ULP_OWNED |
2400 		    PACKET_IN_COMPLETION))) {
2401 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_stale_msg,
2402 			    "Duplicate: iocb=%p cmd=%x status=%x "
2403 			    "error=%x iotag=%d context=%x info=%x",
2404 			    iocbq, (uint8_t)iocbq->iocb.ULPCOMMAND,
2405 			    iocbq->iocb.ULPSTATUS,
2406 			    (uint8_t)iocbq->iocb.un.grsp.perr.statLocalError,
2407 			    (uint16_t)iocbq->iocb.ULPIOTAG,
2408 			    (uint16_t)iocbq->iocb.ULPCONTEXT,
2409 			    (uint8_t)iocbq->iocb.ULPRSVDBYTE);
2410 
2411 			/* Drop this IO immediately */
2412 			return;
2413 		}
2414 
2415 		if (sbp->pkt_flags & PACKET_IN_TIMEOUT) {
2416 			/*
2417 			 * If the packet is tagged for timeout then set the
2418 			 * return codes appropriately
2419 			 */
2420 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
2421 			iocb->un.grsp.perr.statLocalError = IOERR_ABORT_TIMEOUT;
2422 		} else if (sbp->pkt_flags &
2423 		    (PACKET_IN_FLUSH | PACKET_IN_ABORT)) {
2424 			/*
2425 			 * If the packet is tagged for abort then set the
2426 			 * return codes appropriately
2427 			 */
2428 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
2429 			iocb->un.grsp.perr.statLocalError =
2430 			    IOERR_ABORT_REQUESTED;
2431 		}
2432 	}
2433 
2434 	/* Check for IOCB local error */
2435 	if (iocb->ULPSTATUS == IOSTAT_LOCAL_REJECT) {
2436 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_event_msg,
2437 		    "Local reject. ringno=%d iocb=%p cmd=%x "
2438 		    "iotag=%d context=%x info=%x error=%x",
2439 		    cp->channelno, iocb, (uint8_t)iocb->ULPCOMMAND,
2440 		    (uint16_t)iocb->ULPIOTAG, (uint16_t)iocb->ULPCONTEXT,
2441 		    (uint8_t)iocb->ULPRSVDBYTE,
2442 		    (uint8_t)iocb->un.grsp.perr.statLocalError);
2443 	}
2444 
2445 	switch (iocb->ULPCOMMAND) {
2446 		/* RING 0 FCP commands */
2447 	case CMD_FCP_ICMND_CR:
2448 	case CMD_FCP_ICMND_CX:
2449 	case CMD_FCP_IREAD_CR:
2450 	case CMD_FCP_IREAD_CX:
2451 	case CMD_FCP_IWRITE_CR:
2452 	case CMD_FCP_IWRITE_CX:
2453 	case CMD_FCP_ICMND64_CR:
2454 	case CMD_FCP_ICMND64_CX:
2455 	case CMD_FCP_IREAD64_CR:
2456 	case CMD_FCP_IREAD64_CX:
2457 	case CMD_FCP_IWRITE64_CR:
2458 	case CMD_FCP_IWRITE64_CX:
2459 		emlxs_handle_fcp_event(hba, cp, iocbq);
2460 		break;
2461 
2462 #ifdef SFCT_SUPPORT
2463 	case CMD_FCP_TSEND_CX:		/* FCP_TARGET IOCB command */
2464 	case CMD_FCP_TSEND64_CX:	/* FCP_TARGET IOCB command */
2465 	case CMD_FCP_TRECEIVE_CX:	/* FCP_TARGET IOCB command */
2466 	case CMD_FCP_TRECEIVE64_CX:	/* FCP_TARGET IOCB command */
2467 	case CMD_FCP_TRSP_CX:		/* FCP_TARGET IOCB command */
2468 	case CMD_FCP_TRSP64_CX:		/* FCP_TARGET IOCB command */
2469 		if (port->mode == MODE_TARGET) {
2470 			(void) emlxs_fct_handle_fcp_event(hba, cp, iocbq);
2471 		}
2472 		break;
2473 #endif /* SFCT_SUPPORT */
2474 
2475 		/* RING 1 IP commands */
2476 	case CMD_XMIT_BCAST_CN:
2477 	case CMD_XMIT_BCAST_CX:
2478 	case CMD_XMIT_BCAST64_CN:
2479 	case CMD_XMIT_BCAST64_CX:
2480 		(void) emlxs_ip_handle_event(hba, cp, iocbq);
2481 		break;
2482 
2483 	case CMD_XMIT_SEQUENCE_CX:
2484 	case CMD_XMIT_SEQUENCE_CR:
2485 	case CMD_XMIT_SEQUENCE64_CX:
2486 	case CMD_XMIT_SEQUENCE64_CR:
2487 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2488 		case FC_TYPE_IS8802_SNAP:
2489 			(void) emlxs_ip_handle_event(hba, cp, iocbq);
2490 			break;
2491 
2492 		case FC_TYPE_FC_SERVICES:
2493 			(void) emlxs_ct_handle_event(hba, cp, iocbq);
2494 			break;
2495 
2496 		default:
2497 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2498 			    "cmd=%x type=%x status=%x iotag=%d context=%x ",
2499 			    iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
2500 			    iocb->ULPSTATUS, iocb->ULPIOTAG,
2501 			    iocb->ULPCONTEXT);
2502 		}
2503 		break;
2504 
2505 	case CMD_RCV_SEQUENCE_CX:
2506 	case CMD_RCV_SEQUENCE64_CX:
2507 	case CMD_RCV_SEQ64_CX:
2508 	case CMD_RCV_ELS_REQ_CX:	/* Unsolicited ELS frame  */
2509 	case CMD_RCV_ELS_REQ64_CX:	/* Unsolicited ELS frame  */
2510 	case CMD_RCV_ELS64_CX:		/* Unsolicited ELS frame  */
2511 		if (hba->sli_mode <= EMLXS_HBA_SLI3_MODE) {
2512 			(void) emlxs_handle_rcv_seq(hba, cp, iocbq);
2513 		}
2514 		break;
2515 
2516 	case CMD_RCV_SEQ_LIST64_CX:
2517 		(void) emlxs_ip_handle_rcv_seq_list(hba, cp, iocbq);
2518 		break;
2519 
2520 	case CMD_CREATE_XRI_CR:
2521 	case CMD_CREATE_XRI_CX:
2522 		(void) emlxs_handle_create_xri(hba, cp, iocbq);
2523 		break;
2524 
2525 		/* RING 2 ELS commands */
2526 	case CMD_ELS_REQUEST_CR:
2527 	case CMD_ELS_REQUEST_CX:
2528 	case CMD_XMIT_ELS_RSP_CX:
2529 	case CMD_ELS_REQUEST64_CR:
2530 	case CMD_ELS_REQUEST64_CX:
2531 	case CMD_XMIT_ELS_RSP64_CX:
2532 		(void) emlxs_els_handle_event(hba, cp, iocbq);
2533 		break;
2534 
2535 		/* RING 3 CT commands */
2536 	case CMD_GEN_REQUEST64_CR:
2537 	case CMD_GEN_REQUEST64_CX:
2538 		switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2539 #ifdef MENLO_SUPPORT
2540 		case EMLXS_MENLO_TYPE:
2541 			(void) emlxs_menlo_handle_event(hba, cp, iocbq);
2542 			break;
2543 #endif /* MENLO_SUPPORT */
2544 
2545 		case FC_TYPE_FC_SERVICES:
2546 			(void) emlxs_ct_handle_event(hba, cp, iocbq);
2547 			break;
2548 
2549 		default:
2550 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2551 			    "cmd=%x type=%x status=%x iotag=%d context=%x ",
2552 			    iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
2553 			    iocb->ULPSTATUS, iocb->ULPIOTAG,
2554 			    iocb->ULPCONTEXT);
2555 		}
2556 		break;
2557 
2558 	case CMD_ABORT_XRI_CN:	/* Abort fcp command */
2559 
2560 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2561 		    "ABORT_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2562 		    (uint32_t)iocb->un.acxri.abortContextTag,
2563 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2564 		    iocb->un.acxri.parm);
2565 
2566 #ifdef SFCT_SUPPORT
2567 		if (port->mode == MODE_TARGET) {
2568 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2569 		}
2570 #endif /* SFCT_SUPPORT */
2571 		break;
2572 
2573 	case CMD_ABORT_XRI_CX:	/* Abort command */
2574 
2575 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2576 		    "ABORT_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2577 		    (uint32_t)iocb->un.acxri.abortContextTag,
2578 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2579 		    iocb->un.acxri.parm, iocbq->sbp);
2580 
2581 #ifdef SFCT_SUPPORT
2582 		if (port->mode == MODE_TARGET) {
2583 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2584 		}
2585 #endif /* SFCT_SUPPORT */
2586 		break;
2587 
2588 	case CMD_XRI_ABORTED_CX:	/* Handle ABORT condition */
2589 
2590 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2591 		    "XRI_ABORTED_CX: rpi=%d iotag=%d status=%x parm=%x",
2592 		    (uint32_t)iocb->un.acxri.abortContextTag,
2593 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2594 		    iocb->un.acxri.parm);
2595 
2596 #ifdef SFCT_SUPPORT
2597 		if (port->mode == MODE_TARGET) {
2598 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2599 		}
2600 #endif /* SFCT_SUPPORT */
2601 		break;
2602 
2603 	case CMD_CLOSE_XRI_CN:	/* Handle CLOSE condition */
2604 
2605 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2606 		    "CLOSE_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2607 		    (uint32_t)iocb->un.acxri.abortContextTag,
2608 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2609 		    iocb->un.acxri.parm);
2610 
2611 #ifdef SFCT_SUPPORT
2612 		if (port->mode == MODE_TARGET) {
2613 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2614 		}
2615 #endif /* SFCT_SUPPORT */
2616 		break;
2617 
2618 	case CMD_CLOSE_XRI_CX:	/* Handle CLOSE condition */
2619 
2620 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2621 		    "CLOSE_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2622 		    (uint32_t)iocb->un.acxri.abortContextTag,
2623 		    (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2624 		    iocb->un.acxri.parm, iocbq->sbp);
2625 
2626 #ifdef SFCT_SUPPORT
2627 		if (port->mode == MODE_TARGET) {
2628 			(void) emlxs_fct_handle_abort(hba, cp, iocbq);
2629 		}
2630 #endif /* SFCT_SUPPORT */
2631 		break;
2632 
2633 	case CMD_ADAPTER_MSG:
2634 		/* Allows debug adapter firmware messages to print on host */
2635 		bzero(buffer, sizeof (buffer));
2636 		bcopy((uint8_t *)iocb, buffer, MAX_MSG_DATA);
2637 
2638 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_msg, "%s", buffer);
2639 
2640 		break;
2641 
2642 	case CMD_QUE_RING_LIST64_CN:
2643 	case CMD_QUE_RING_BUF64_CN:
2644 		break;
2645 
2646 	case CMD_ASYNC_STATUS:
2647 		emlxs_handle_async_event(hba, cp, iocbq);
2648 		break;
2649 
2650 	case CMD_XMIT_BLS_RSP64_CX:
2651 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2652 		    "CMD_XMIT_BLS_RSP64_CX: sbp = %p", sbp);
2653 
2654 		/*
2655 		 * The exchange should have been already freed in the wqe_cmpl
2656 		 * so just free up the pkt here.
2657 		 */
2658 		pkt = PRIV2PKT(sbp);
2659 		emlxs_pkt_free(pkt);
2660 		break;
2661 
2662 	default:
2663 		if (iocb->ULPCOMMAND == 0) {
2664 			break;
2665 		}
2666 
2667 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2668 		    "cmd=%x status=%x iotag=%d context=%x", iocb->ULPCOMMAND,
2669 		    iocb->ULPSTATUS, iocb->ULPIOTAG, iocb->ULPCONTEXT);
2670 
2671 		break;
2672 	}	/* switch(entry->ULPCOMMAND) */
2673 
2674 	return;
2675 
2676 } /* emlxs_proc_channel_event() */
2677 
2678 
2679 extern char *
2680 emlxs_ffstate_xlate(uint32_t state)
2681 {
2682 	static char buffer[32];
2683 	uint32_t i;
2684 	uint32_t count;
2685 
2686 	count = sizeof (emlxs_ffstate_table) / sizeof (emlxs_table_t);
2687 	for (i = 0; i < count; i++) {
2688 		if (state == emlxs_ffstate_table[i].code) {
2689 			return (emlxs_ffstate_table[i].string);
2690 		}
2691 	}
2692 
2693 	(void) snprintf(buffer, sizeof (buffer), "state=0x%x", state);
2694 	return (buffer);
2695 
2696 } /* emlxs_ffstate_xlate() */
2697 
2698 
2699 extern char *
2700 emlxs_ring_xlate(uint32_t ringno)
2701 {
2702 	static char buffer[32];
2703 	uint32_t i;
2704 	uint32_t count;
2705 
2706 	count = sizeof (emlxs_ring_table) / sizeof (emlxs_table_t);
2707 	for (i = 0; i < count; i++) {
2708 		if (ringno == emlxs_ring_table[i].code) {
2709 			return (emlxs_ring_table[i].string);
2710 		}
2711 	}
2712 
2713 	(void) snprintf(buffer, sizeof (buffer), "ring=0x%x", ringno);
2714 	return (buffer);
2715 
2716 } /* emlxs_ring_xlate() */
2717 
2718 
2719 extern char *
2720 emlxs_pci_cap_xlate(uint32_t id)
2721 {
2722 	static char buffer[32];
2723 	uint32_t i;
2724 	uint32_t count;
2725 
2726 	count = sizeof (emlxs_pci_cap) / sizeof (emlxs_table_t);
2727 	for (i = 0; i < count; i++) {
2728 		if (id == emlxs_pci_cap[i].code) {
2729 			return (emlxs_pci_cap[i].string);
2730 		}
2731 	}
2732 
2733 	(void) snprintf(buffer, sizeof (buffer), "PCI_CAP_ID_%02X", id);
2734 	return (buffer);
2735 
2736 } /* emlxs_pci_cap_xlate() */
2737 
2738 
2739 extern char *
2740 emlxs_pci_ecap_xlate(uint32_t id)
2741 {
2742 	static char buffer[32];
2743 	uint32_t i;
2744 	uint32_t count;
2745 
2746 	count = sizeof (emlxs_pci_ecap) / sizeof (emlxs_table_t);
2747 	for (i = 0; i < count; i++) {
2748 		if (id == emlxs_pci_ecap[i].code) {
2749 			return (emlxs_pci_ecap[i].string);
2750 		}
2751 	}
2752 
2753 	(void) snprintf(buffer, sizeof (buffer), "PCI_EXT_CAP_ID_%02X", id);
2754 	return (buffer);
2755 
2756 } /* emlxs_pci_ecap_xlate() */
2757 
2758 
2759 extern void
2760 emlxs_pcix_mxr_update(emlxs_hba_t *hba, uint32_t verbose)
2761 {
2762 	emlxs_port_t *port = &PPORT;
2763 	MAILBOXQ *mbq;
2764 	MAILBOX *mb;
2765 	emlxs_config_t *cfg;
2766 	uint32_t value;
2767 
2768 	cfg = &CFG;
2769 
2770 xlate:
2771 
2772 	switch (cfg[CFG_PCI_MAX_READ].current) {
2773 	case 512:
2774 		value = 0;
2775 		break;
2776 
2777 	case 1024:
2778 		value = 1;
2779 		break;
2780 
2781 	case 2048:
2782 		value = 2;
2783 		break;
2784 
2785 	case 4096:
2786 		value = 3;
2787 		break;
2788 
2789 	default:
2790 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2791 		    "PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
2792 		    cfg[CFG_PCI_MAX_READ].current, cfg[CFG_PCI_MAX_READ].def);
2793 
2794 		cfg[CFG_PCI_MAX_READ].current = cfg[CFG_PCI_MAX_READ].def;
2795 		goto xlate;
2796 	}
2797 
2798 	if ((mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)),
2799 	    KM_SLEEP)) == 0) {
2800 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2801 		    "PCI_MAX_READ: Unable to allocate mailbox buffer.");
2802 		return;
2803 	}
2804 	mb = (MAILBOX *)mbq;
2805 
2806 	emlxs_mb_set_var(hba, mbq, 0x00100506, value);
2807 
2808 	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2809 		if (verbose || (mb->mbxStatus != 0x12)) {
2810 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2811 			    "PCI_MAX_READ: Unable to update. "
2812 			    "status=%x value=%d (%d bytes)",
2813 			    mb->mbxStatus, value,
2814 			    cfg[CFG_PCI_MAX_READ].current);
2815 		}
2816 	} else {
2817 		if (verbose &&
2818 		    (cfg[CFG_PCI_MAX_READ].current !=
2819 		    cfg[CFG_PCI_MAX_READ].def)) {
2820 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2821 			    "PCI_MAX_READ: Updated. %d bytes",
2822 			    cfg[CFG_PCI_MAX_READ].current);
2823 		}
2824 	}
2825 
2826 	(void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
2827 
2828 	return;
2829 
2830 } /* emlxs_pcix_mxr_update */
2831 
2832 
2833 
2834 extern uint32_t
2835 emlxs_get_key(emlxs_hba_t *hba, MAILBOXQ *mbq)
2836 {
2837 	emlxs_port_t *port = &PPORT;
2838 	MAILBOX *mb = (MAILBOX *)mbq;
2839 	uint32_t npname0, npname1;
2840 	uint32_t tmpkey, theKey;
2841 	uint16_t key850;
2842 	uint32_t t1, t2, t3, t4;
2843 	uint32_t ts;
2844 
2845 #define	SEED 0x876EDC21
2846 
2847 	/* This key is only used currently for SBUS adapters */
2848 	if (hba->bus_type != SBUS_FC) {
2849 		return (0);
2850 	}
2851 
2852 	tmpkey = mb->un.varWords[30];
2853 	EMLXS_STATE_CHANGE(hba, FC_INIT_NVPARAMS);
2854 
2855 	emlxs_mb_read_nv(hba, mbq);
2856 	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2857 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2858 		    "Unable to read nvram. cmd=%x status=%x", mb->mbxCommand,
2859 		    mb->mbxStatus);
2860 
2861 		return (0);
2862 	}
2863 	npname0 = mb->un.varRDnvp.portname[0];
2864 	npname1 = mb->un.varRDnvp.portname[1];
2865 
2866 	key850 = (uint16_t)((tmpkey & 0x00FFFF00) >> 8);
2867 	ts = (uint16_t)(npname1 + 1);
2868 	t1 = ts * key850;
2869 	ts = (uint16_t)((npname1 >> 16) + 1);
2870 	t2 = ts * key850;
2871 	ts = (uint16_t)(npname0 + 1);
2872 	t3 = ts * key850;
2873 	ts = (uint16_t)((npname0 >> 16) + 1);
2874 	t4 = ts * key850;
2875 	theKey = SEED + t1 + t2 + t3 + t4;
2876 
2877 	return (theKey);
2878 
2879 } /* emlxs_get_key() */
2880 
2881 
2882 extern void
2883 emlxs_fw_show(emlxs_hba_t *hba)
2884 {
2885 	emlxs_port_t *port = &PPORT;
2886 	uint32_t i;
2887 
2888 	/* Display firmware library one time */
2889 	for (i = 0; i < emlxs_fw_count; i++) {
2890 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_library_msg, "%s",
2891 		    emlxs_fw_table[i].label);
2892 	}
2893 
2894 	return;
2895 
2896 } /* emlxs_fw_show() */
2897 
2898 
2899 #ifdef MODFW_SUPPORT
2900 extern void
2901 emlxs_fw_load(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2902 {
2903 	emlxs_port_t *port = &PPORT;
2904 	int (*emlxs_fw_get)(emlxs_firmware_t *);
2905 	int err;
2906 	char name[64];
2907 
2908 	/* Make sure image is unloaded and image buffer pointer is clear */
2909 	emlxs_fw_unload(hba, fw);
2910 
2911 	err = 0;
2912 	hba->fw_modhandle =
2913 	    ddi_modopen(EMLXS_FW_MODULE, KRTLD_MODE_FIRST, &err);
2914 	if (!hba->fw_modhandle) {
2915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2916 		    "Unable to load firmware module. error=%d", err);
2917 
2918 		return;
2919 	} else {
2920 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2921 		    "Firmware module loaded.");
2922 	}
2923 
2924 	(void) snprintf(name, sizeof (name), "%s_fw_get", DRIVER_NAME);
2925 	err = 0;
2926 	emlxs_fw_get =
2927 	    (int (*)())ddi_modsym(hba->fw_modhandle, name, &err);
2928 	if ((void *)emlxs_fw_get == NULL) {
2929 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2930 		    "%s not present. error=%d", name, err);
2931 
2932 		emlxs_fw_unload(hba, fw);
2933 		return;
2934 	}
2935 
2936 	if (emlxs_fw_get(fw)) {
2937 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2938 		    "Invalid firmware image module found. %s", fw->label);
2939 
2940 		emlxs_fw_unload(hba, fw);
2941 		return;
2942 	}
2943 
2944 	return;
2945 
2946 } /* emlxs_fw_load() */
2947 
2948 
2949 extern void
2950 emlxs_fw_unload(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2951 {
2952 	emlxs_port_t *port = &PPORT;
2953 
2954 	/* Clear the firmware image */
2955 	fw->image = NULL;
2956 	fw->size = 0;
2957 
2958 	if (hba->fw_modhandle) {
2959 		/* Close the module */
2960 		(void) ddi_modclose(hba->fw_modhandle);
2961 		hba->fw_modhandle = NULL;
2962 
2963 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2964 		    "Firmware module unloaded.");
2965 	}
2966 
2967 	return;
2968 
2969 } /* emlxs_fw_unload() */
2970 #endif /* MODFW_SUPPORT */
2971 
2972 
2973 static void
2974 emlxs_pci_cap_offsets(emlxs_hba_t *hba)
2975 {
2976 	emlxs_port_t *port = &PPORT;
2977 	uint32_t reg;
2978 	uint8_t	offset;
2979 	uint8_t	next;
2980 	uint8_t	id;
2981 	uint16_t eoffset;
2982 	uint16_t enext;
2983 	uint8_t eversion;
2984 	uint16_t eid;
2985 
2986 	/* Read PCI capbabilities */
2987 
2988 	bzero(hba->pci_cap_offset, sizeof (hba->pci_cap_offset));
2989 
2990 	/* Read first offset */
2991 	offset = PCI_CAP_POINTER;
2992 	offset = ddi_get8(hba->pci_acc_handle,
2993 	    (uint8_t *)(hba->pci_addr + offset));
2994 
2995 	while (offset >= PCI_CAP_PTR_OFF) {
2996 		/* Read the cap */
2997 		reg = ddi_get32(hba->pci_acc_handle,
2998 		    (uint32_t *)(hba->pci_addr + offset));
2999 
3000 		id = ((reg >> PCI_CAP_ID_SHIFT) & PCI_CAP_ID_MASK);
3001 		next = ((reg >> PCI_CAP_NEXT_PTR_SHIFT) &
3002 		    PCI_CAP_NEXT_PTR_MASK);
3003 
3004 		if ((id < PCI_CAP_MAX_PTR) &&
3005 		    (hba->pci_cap_offset[id] == 0)) {
3006 			hba->pci_cap_offset[id] = offset;
3007 		}
3008 
3009 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3010 		    "%s: offset=0x%x next=0x%x",
3011 		    emlxs_pci_cap_xlate(id), offset, next);
3012 
3013 		offset = next;
3014 	}
3015 
3016 	/* Workaround for BE adapters */
3017 	if ((hba->pci_cap_offset[PCI_CAP_ID_VS] == 0) &&
3018 	    (hba->model_info.chip & EMLXS_BE_CHIPS)) {
3019 		hba->pci_cap_offset[PCI_CAP_ID_VS] = 0x54;
3020 
3021 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3022 		    "%s: offset=0x%x  Added.",
3023 		    emlxs_pci_cap_xlate(PCI_CAP_ID_VS),
3024 		    hba->pci_cap_offset[PCI_CAP_ID_VS]);
3025 	}
3026 
3027 	if (! hba->pci_cap_offset[PCI_CAP_ID_PCI_E]) {
3028 		/* It's not a PCIE adapter. */
3029 		return;
3030 	}
3031 
3032 	/* Read PCI Extended capbabilities */
3033 
3034 	bzero(hba->pci_ecap_offset, sizeof (hba->pci_ecap_offset));
3035 
3036 	/* Set first offset */
3037 	eoffset = PCIE_EXT_CAP;
3038 
3039 	while (eoffset >= PCIE_EXT_CAP) {
3040 		/* Read the cap */
3041 		reg = ddi_get32(hba->pci_acc_handle,
3042 		    (uint32_t *)(hba->pci_addr + eoffset));
3043 
3044 		eid = ((reg >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK);
3045 		eversion = ((reg >> PCIE_EXT_CAP_VER_SHIFT) &
3046 		    PCIE_EXT_CAP_VER_MASK);
3047 		enext = ((reg >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
3048 		    PCIE_EXT_CAP_NEXT_PTR_MASK);
3049 
3050 		if ((eid < PCI_EXT_CAP_MAX_PTR) &&
3051 		    (hba->pci_ecap_offset[eid] == 0)) {
3052 			hba->pci_ecap_offset[eid] = eoffset;
3053 		}
3054 
3055 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3056 		    "%s: offset=0x%x version=0x%x next=0x%x",
3057 		    emlxs_pci_ecap_xlate(eid),
3058 		    eoffset, eversion, enext);
3059 
3060 		eoffset = enext;
3061 	}
3062 
3063 	return;
3064 
3065 } /* emlxs_pci_cap_offsets() */
3066