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