emlxs_hba.c revision 825277341c15b6b0d2c4b8b622ae7b1d2bdc0390
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#define EMLXS_FW_TABLE_DEF
#define EMLXS_MODEL_DEF
#include <emlxs.h>
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
#ifdef MSI_SUPPORT
#endif /* MSI_SUPPORT */
{FC_FCP_RING, "FCP Ring"},
{FC_IP_RING, "IP Ring"},
{FC_ELS_RING, "ELS Ring"},
{FC_CT_RING, "CT Ring"}
}; /* emlxs_ring_table */
{0, "NULL"},
{FC_ERROR, "ERROR"},
{FC_KILLED, "KILLED"},
{FC_WARM_START, "WARM_START"},
{FC_INIT_START, "INIT_START"},
{FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
{FC_INIT_REV, "INIT_REV"},
{FC_INIT_CFGPORT, "INIT_CFGPORT"},
{FC_INIT_CFGRING, "INIT_CFGRING"},
{FC_INIT_INITLINK, "INIT_INITLINK"},
{FC_LINK_DOWN, "LINK_DOWN"},
{FC_LINK_UP, "LINK_UP"},
{FC_CLEAR_LA, "CLEAR_LA"},
{FC_READY, "READY"}
}; /* emlxs_ffstate_table */
#ifdef MSI_SUPPORT
/* EMLXS_INTR_INIT */
{
char s_type[16];
int32_t i;
char buf[64];
}
return (DDI_SUCCESS);
}
/* Set max interrupt count if not specified */
if (max == 0) {
} else {
max = 1;
}
}
/* Filter max interrupt count with adapter model specification */
}
/* Get the available interrupt types from the kernel */
types = 0;
if ((ret != DDI_SUCCESS)) {
"MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
/* Default to fixed type */
}
/* Check if fixed interrupts are being forced */
}
/* Check if MSI interrupts are being forced */
}
/* Set interrupt type and interrupt count */
type = 0;
/* Check if MSIX is fully supported */
if ((types & DDI_INTR_TYPE_MSIX) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
ret =
&nintrs);
goto initialize;
}
}
/* Check if MSI is fully supported */
if ((types & DDI_INTR_TYPE_MSI) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
ret =
goto initialize;
}
}
/* Check if fixed interrupts are fully supported */
if ((types & DDI_INTR_TYPE_FIXED) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
ret =
&nintrs);
if (ret == DDI_SUCCESS) {
goto initialize;
}
}
goto init_failed;
pass++;
mode = 0;
actual = 0;
hilevel_pri = 0;
if (pass == 1) {
"MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
}
/* Validate interrupt count */
if (count >= 8) {
count = 8;
} else if (count >= 4) {
count = 4;
} else if (count >= 2) {
count = 2;
} else {
count = 1;
}
/* Allocate an array of interrupt handles */
htable =
KM_SLEEP);
/* Allocate 'count' interrupts */
ret =
"MSI: Unable to allocate interrupts. error=%d", ret);
goto init_failed;
}
/* Validate actual count */
if (actual >= 8) {
new_actual = 8;
} else if (actual >= 4) {
new_actual = 4;
} else if (actual >= 2) {
new_actual = 2;
} else {
new_actual = 1;
}
if (new_actual < actual) {
/* Free extra handles */
for (i = new_actual; i < actual; i++) {
(void) ddi_intr_free(htable[i]);
}
actual = new_actual;
}
/* Allocate a new array of interrupt handles */
KM_SLEEP);
/* Copy old array to new array */
(actual * sizeof (ddi_intr_handle_t)));
/* Free the old array */
htable = new_htable;
}
/* Allocate interrupt priority table */
intr_pri =
KM_SLEEP);
/* Allocate interrupt capability table */
/* Get minimum hilevel priority */
/* Fill the priority and capability tables */
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_get_pri(%d) failed. "
"handle=%p ret=%d",
/* Clean up the interrupts */
goto init_failed;
}
if (intr_pri[i] >= hilevel_pri) {
"MSI: Interrupt(%d) level too high. "
"pri=0x%x hilevel=0x%x",
i, intr_pri[i], hilevel_pri);
/* Clean up the interrupts */
goto init_failed;
}
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_get_cap(%d) failed. "
"handle=%p ret=%d",
/* Clean up the interrupts */
goto init_failed;
}
"MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
}
/* Set mode */
switch (count) {
case 8:
break;
case 4:
break;
case 2:
break;
default:
}
/* Save the info */
/* Adjust number of channels based on intr_count */
}
for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
}
/* Set flag to indicate support */
/* Create the interrupt threads */
for (i = 0; i < hba->chan_count; i++) {
}
return (DDI_SUCCESS);
if (intr_cap) {
}
if (intr_pri) {
}
if (htable) {
/* Process the interrupt handlers */
for (i = 0; i < actual; i++) {
/* Free the handle[i] */
(void) ddi_intr_free(htable[i]);
}
}
/* Initialize */
hba->intr_count = 0;
if (type == DDI_INTR_TYPE_MSIX) {
goto begin;
} else if (type == DDI_INTR_TYPE_MSI) {
goto begin;
}
"MSI: Unable to initialize interrupts");
return (DDI_FAILURE);
} /* emlxs_msi_init() */
/* EMLXS_INTR_UNINIT */
{
int32_t i;
return (emlxs_intx_uninit(hba));
}
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
* "MSI: emlxs_msi_uninit called. flags=%x",
* hba->intr_flags);
*/
/* Make sure interrupts have been removed first */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Check if the interrupts are still initialized */
return (DDI_SUCCESS);
}
/* Get handle table parameters */
/* Clean up */
hba->intr_count = 0;
if (intr_cap) {
}
if (intr_pri) {
}
if (htable) {
/* Process the interrupt handlers */
for (i = 0; i < count; ++i) {
/* Free the handle[i] */
}
}
/* Destroy the intr locks */
for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
}
/* Destroy the interrupt threads */
for (i = 0; i < hba->chan_count; i++) {
}
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
* "MSI: emlxs_msi_uninit done. flags=%x",
* hba->intr_flags);
*/
return (DDI_SUCCESS);
} /* emlxs_msi_uninit() */
/* EMLXS_INTR_ADD */
{
int32_t i;
return (emlxs_intx_add(hba));
}
/* Check if interrupts have already been added */
return (DDI_SUCCESS);
}
/* Check if interrupts have been initialized */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Get handle table parameters */
/* Add the interrupt handlers */
for (i = 0; i < count; ++i) {
/* add handler for handle[i] */
ret =
(char *)hba, (char *)((unsigned long)i));
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_add_handler(%d) failed. "
"handle=%p ret=%d",
/* Process the remaining interrupt handlers */
while (i) {
/* Decrement i */
i--;
/* Remove the handler */
}
return (DDI_FAILURE);
}
}
/* Enable the interrupts */
if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_block_enable(%d) failed. ret=%d",
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_enable(%d) failed. "
"ret=%d",
i, ret);
}
}
}
} else {
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_enable(%d) failed. ret=%d",
i, ret);
}
}
}
/* Set flag to indicate support */
return (DDI_SUCCESS);
} /* emlxs_msi_add() */
/* EMLXS_INTR_REMOVE */
{
int32_t i;
return (emlxs_intx_remove(hba));
}
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
* "MSI: emlxs_msi_remove called. flags=%x",
* hba->intr_flags);
*/
/* Check if interrupts have already been removed */
return (DDI_SUCCESS);
}
/* Disable all adapter interrupts */
/* Get handle table parameters */
/* Disable the interrupts */
if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_block_disable(%d) failed. ret=%d",
for (i = 0; i < count; i++) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_disable(%d) failed. "
"ret=%d",
i, ret);
}
}
}
} else {
for (i = 0; i < count; i++) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_disable(%d) failed. ret=%d",
i, ret);
}
}
}
/* Process the interrupt handlers */
for (i = 0; i < count; i++) {
/* Remove the handler */
}
return (DDI_SUCCESS);
} /* emlxs_msi_remove() */
#endif /* MSI_SUPPORT */
/* EMLXS_INTR_INIT */
/* ARGSUSED */
{
uint32_t i;
char buf[64];
/* Check if interrupts have already been initialized */
return (DDI_SUCCESS);
}
/* Check if adapter is flagged for INTX support */
"INTX: %s does not support INTX. flags=0x%x",
return (DDI_FAILURE);
}
/*
* Interrupt number '0' is a high-level interrupt. This driver
* does not support having its interrupts mapped above scheduler
* priority; i.e., we always expect to be able to call general
* kernel routines that may invoke the scheduler.
*/
"INTX: High-level interrupt not supported.");
return (DDI_FAILURE);
}
/* Get an iblock cookie */
ret =
if (ret != DDI_SUCCESS) {
"INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
return (ret);
}
/* Adjust number of channels based on intr_count */
}
/* Create the interrupt threads */
for (i = 0; i < hba->chan_count; i++) {
}
return (DDI_SUCCESS);
} /* emlxs_intx_init() */
/* EMLXS_INTR_UNINIT */
{
uint32_t i;
/* Make sure interrupts have been removed */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Check if the interrupts are still initialized */
return (DDI_SUCCESS);
}
/* Create the interrupt threads */
for (i = 0; i < hba->chan_count; i++) {
}
return (DDI_SUCCESS);
} /* emlxs_intx_uninit() */
/*
* This is the legacy method for adding interrupts in Solaris
* EMLXS_INTR_ADD
*/
{
/* Check if interrupts have already been added */
return (DDI_SUCCESS);
}
/* Check if interrupts have been initialized */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* add intrrupt handler routine */
(ddi_idevice_cookie_t *)0,
if (ret != DDI_SUCCESS) {
"INTX: ddi_add_intr failed. ret=%d", ret);
return (ret);
}
return (DDI_SUCCESS);
} /* emlxs_intx_add() */
/* EMLXS_INTR_REMOVE */
{
/* Check if interrupts have already been removed */
return (DDI_SUCCESS);
}
/* Diable all adapter interrupts */
/* Remove the interrupt */
return (DDI_SUCCESS);
} /* emlxs_intx_remove() */
extern void
{
char *cptr;
/*
* This routine modifies the link-speed config parameter entry
* based on adapter capabilities
*/
cptr += 26;
hi = 0;
cptr += 7;
hi = 1;
}
cptr += 7;
hi = 2;
}
cptr += 7;
hi = 4;
}
cptr += 7;
hi = 8;
}
cptr += 9;
hi = 10;
}
/* Now revalidate the current parameter setting */
return;
} /* emlxs_process_link_speed() */
/*
* emlxs_parse_vpd()
*
* This routine will parse the VPD data
*/
extern int
{
char tag[3];
uint32_t n;
uint32_t block_index = 0;
char buffer[128];
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "block_index = %x", block_index);
*/
switch (vpd_buf[block_index]) {
case 0x82:
index = block_index;
index += 1;
index += 1;
index += 1;
block_index = index;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "block_size = %x", block_size);
*/
n = sizeof (buffer);
break;
case 0x90:
index = block_index;
index += 1;
index += 1;
index += 1;
block_index = index;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "block_size = %x", block_size);
*/
/* Scan for sub-blocks */
while ((sub_index < block_index) &&
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "sub_index = %x", sub_index);
*/
tag[2] = 0;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "sub_size = %x", sub_size);
*/
n = sizeof (buffer);
/*
* Look for Engineering Change (EC)
*/
&emlxs_vpd_msg, "EC: %s",
vpd->eng_change);
}
/*
* Look for Manufacturer (MN)
*/
buffer);
&emlxs_vpd_msg, "MN: %s",
vpd->manufacturer);
}
/*
* Look for Serial Number (SN)
*/
&emlxs_vpd_msg, "SN: %s",
vpd->serial_num);
/* Validate the serial number */
0 ||
0) {
vpd->serial_num[0] = 0;
}
}
/*
* Look for Part Number (PN)
*/
&emlxs_vpd_msg, "PN: %s",
}
/*
* Look for (V0)
*/
/* Not used */
}
/*
* Look for model description (V1)
*/
&emlxs_vpd_msg, "Desc: %s",
vpd->model_desc);
}
/*
* Look for model (V2)
*/
&emlxs_vpd_msg, "Model: %s",
}
/*
* Look for program type (V3)
*/
&emlxs_vpd_msg, "Prog Types: %s",
vpd->prog_types);
}
/*
* Look for port number (V4)
*/
vpd->port_index =
&emlxs_vpd_msg, "Port: %s",
port_num : "not applicable");
}
/*
* Look for checksum (RV)
*/
/* Not used */
&emlxs_vpd_msg, "Checksum: 0x%x",
buffer[0]);
}
else {
/* Generic */
&emlxs_vpd_msg, "Tag: %s: %s",
}
}
break;
case 0x78:
finished = 1;
break;
default:
"Unknown block: %x %x %x %x %x %x %x %x",
return (0);
}
}
return (1);
} /* emlxs_parse_vpd */
/*
* emlxs_parse_fcoe()
*
* This routine will parse the VPD data
*/
extern int
{
int i;
/* Validate the config region 23 signature */
return (0);
}
/* Search the config region 23, for FCOE Parameters record */
i = 4;
}
if (*(fcoep+i) == 0xA0) {
"Found FCOE Params (A0):%d x%x",
sizeof (tlv_fcoe_t));
}
/* Search the config region 23, for FCF record */
i = 4;
}
if (*(fcoep+i) == 0xA1) {
sizeof (tlv_fcfconnectlist_t));
}
return (1);
} /* emlxs_parse_fcoe */
static uint32_t
{
return (rev & 0xf);
} /* End emlxs_decode_biu_rev */
static uint32_t
{
} /* End emlxs_decode_endec_rev */
extern void
{
case EMLXS_HBA_SLI4_MODE:
break;
case EMLXS_HBA_SLI3_MODE:
break;
case EMLXS_HBA_SLI2_MODE:
break;
case EMLXS_HBA_SLI1_MODE:
break;
default:
}
} else {
}
return;
} /* emlxs_decode_firmware_rev() */
extern void
{
char c;
return;
}
c = 0;
switch (b4) {
case 0:
c = 'n';
break;
case 1:
c = 'a';
break;
case 2:
c = 'b';
break;
case 3:
if ((version & 0x0000000f)) {
c = 'x';
}
break;
}
if (c == 0) {
} else {
}
return;
} /* emlxs_decode_version() */
extern void
{
uint32_t i;
char name[16];
/* bige is TRUE if the data format is big endian */
if (bige) {
/* Data format big Endian */
for (i = 0; i < sizeof (name); i++) {
if (name[i] == 0x20) {
name[i] = 0;
}
}
} else {
/* Data format little Endian */
for (i = 0; i < sizeof (name); i++) {
if (name[i] == 0x20) {
name[i] = 0;
}
}
}
return;
} /* emlxs_decode_label() */
extern uint32_t
{
char *ptr;
if (*str == 0) {
return (0);
}
return (0);
}
/* Get max digits of value */
/* Position pointer to end of string */
/* Process string backwards */
/* check for base 10 numbers */
digits--;
} else if (base == 16) {
/* Check for base 16 numbers */
value +=
digits--;
value +=
digits--;
} else if (factor > 1) {
break;
}
} else if (factor > 1) {
break;
}
}
return (value);
} /* emlxs_strtol() */
extern uint64_t
{
char *ptr;
if (*str == 0) {
return (0);
}
return (0);
}
/* Get max digits of value */
/* Position pointer to end of string */
/* Process string backwards */
/* check for base 10 numbers */
digits--;
} else if (base == 16) {
/* Check for base 16 numbers */
value +=
digits--;
value +=
digits--;
} else if (factor > 1) {
break;
}
} else if (factor > 1) {
break;
}
}
return (value);
} /* emlxs_strtoll() */
extern void
{
uint32_t i;
char *ptr;
char types_buffer[256];
char *types;
while (*types) {
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
*/
/* Move the str pointer */
}
types += 4;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
*/
/* Move the str pointer */
}
types += 4;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T20[%d]: 0x%x", i-1, model->pt_20[i-1]);
*/
/* Move the str pointer */
}
} else {
"Unknown prog type string = %s", types);
break;
}
}
return;
} /* emlxs_parse_prog_types() */
extern void
{
uint32_t i;
char buffer[256];
/* Rebuild the prog type string */
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
if (found) {
/* Terminate at the last comma in string */
}
return;
} /* emlxs_build_prog_types() */
extern uint32_t
{
uint32_t i;
sizeof (emlxs_model_t));
return (0);
}
/* Read the PCI device id */
pci_id =
/* Find matching adapter model */
for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
sizeof (emlxs_model_t));
found = 1;
break;
}
}
/* If not found then use the unknown model */
if (!found) {
sizeof (emlxs_model_t));
return (0);
}
} else { /* PCI model */
sizeof (emlxs_model_t));
return (0);
}
/* Read the PCI device id */
/* Read the PCI Subsystem id */
ssdid =
}
/* Read the Cache Line reg */
/* Check for the multifunction bit being set */
channels = 2;
} else {
channels = 1;
}
/* If device ids are unique, then use them for search */
if (channels > 1) {
/*
* Find matching adapter model using
* device_id, ssdid and channels
*/
for (i = 1; i < emlxs_pci_model_count; i++) {
if (emlxs_pci_model[i].device_id ==
device_id &&
emlxs_pci_model[i].channels ==
channels) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
found = 1;
break;
}
}
} else {
/*
* Find matching adapter model using
* device_id and ssdid
*/
for (i = 1; i < emlxs_pci_model_count; i++) {
if (emlxs_pci_model[i].device_id ==
device_id &&
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
found = 1;
break;
}
}
}
}
/* If adapter not found, try again */
if (!found) {
/* Find matching adapter model */
for (i = 1; i < emlxs_pci_model_count; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
found = 1;
break;
}
}
}
/* If adapter not found, try one last time */
if (!found) {
/* Find matching adapter model */
for (i = 1; i < emlxs_pci_model_count; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
found = 1;
break;
}
}
}
/* If not found, set adapter to unknown */
if (!found) {
sizeof (emlxs_model_t));
return (0);
}
#ifndef SATURN_MSI_SUPPORT
/*
* This will disable MSI support for Saturn adapter's
* due to a PCI bus issue
*/
}
#endif /* !SATURN_MSI_SUPPORT */
#ifdef MSI_SUPPORT
/* Verify MSI support */
/* Scan for MSI capabilities register */
offset =
offset &= 0xff;
while (offset) {
reg =
break;
}
}
if (offset) {
} else {
hba->msi_cap_offset = 0;
"MSI: control_reg capability not found!");
}
}
/* Verify MSI-X support */
/* Scan for MSI capabilities register */
offset =
offset &= 0xff;
while (offset) {
reg =
break;
}
}
if (offset) {
} else {
hba->msix_cap_offset = 0;
"MSIX: control_reg capability not found!");
}
}
#endif /* MSI_SUPPORT */
}
/* Parse the property for PCI function, device and bus no. */
ddi_prop_free((void *)prop);
}
} else {
}
#ifdef FMA_SUPPORT
!= DDI_FM_OK) {
return (0);
}
#endif /* FMA_SUPPORT */
return (1);
} /* emlxs_init_adapter_info() */
/* ARGSUSED */
static void
{
uint32_t *w;
int i, j;
return;
}
case 0x0100: /* Temp Warning */
"Adapter is very hot (%d �C). Take corrective action.",
iocb->ULPCONTEXT);
break;
case 0x0101: /* Temp Safe */
"Adapter temperature now safe (%d �C).",
iocb->ULPCONTEXT);
break;
default:
for (i = 0, j = 0; i < 8; i++, j += 2) {
"(Word[%d]=%x Word[%d]=%x)", j, w[j], j + 1,
w[j + 1]);
}
}
return;
} /* emlxs_handle_async_event() */
/* ARGSUSED */
extern void
{
/* Attempt a link reset to recover */
return;
} /* emlxs_reset_link_thread() */
/* ARGSUSED */
extern void
{
/* Attempt a full hardware reset to recover */
}
return;
} /* emlxs_restart_thread() */
/* ARGSUSED */
extern void
{
return;
}
"Shutting down...");
/* Take adapter offline and leave it there */
(void) emlxs_offline(hba);
/*
* Dump is not defined for SLI4, so just
* reset the HBA for now.
*/
} else {
hba->temperature);
} else {
}
}
return;
} /* emlxs_shutdown_thread() */
/* ARGSUSED */
extern void
{
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
* "emlxs_proc_channel: channel=%d", cp->channelno);
*/
}
}
return;
} /* emlxs_proc_channel() */
/*
* Called from SLI ring event routines to process a rsp ring IOCB.
*/
void
{
#ifdef DEBUG_CMPL_IOCB
#endif
if (sbp) {
PACKET_IN_COMPLETION))) {
"Duplicate: iocb=%p cmd=%x status=%x "
"error=%x iotag=%x context=%x info=%x",
/* Drop this IO immediately */
return;
}
/*
* If the packet is tagged for timeout then set the
* return codes appropriately
*/
(PACKET_IN_FLUSH | PACKET_IN_ABORT)) {
/*
* If the packet is tagged for abort then set the
* return codes appropriately
*/
}
}
/* Check for IOCB local error */
"Local reject. ringno=%d iocb=%p cmd=%x "
"iotag=%x context=%x info=%x error=%x",
}
switch (iocb->ULPCOMMAND) {
/* RING 0 FCP commands */
case CMD_FCP_ICMND_CR:
case CMD_FCP_ICMND_CX:
case CMD_FCP_IREAD_CR:
case CMD_FCP_IREAD_CX:
case CMD_FCP_IWRITE_CR:
case CMD_FCP_IWRITE_CX:
case CMD_FCP_ICMND64_CR:
case CMD_FCP_ICMND64_CX:
case CMD_FCP_IREAD64_CR:
case CMD_FCP_IREAD64_CX:
case CMD_FCP_IWRITE64_CR:
case CMD_FCP_IWRITE64_CX:
break;
#ifdef SFCT_SUPPORT
case CMD_FCP_TSEND_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TSEND64_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRECEIVE_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRECEIVE64_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRSP_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRSP64_CX: /* FCP_TARGET IOCB command */
break;
#endif /* SFCT_SUPPORT */
/* RING 1 IP commands */
case CMD_XMIT_BCAST_CN:
case CMD_XMIT_BCAST_CX:
case CMD_XMIT_BCAST64_CN:
case CMD_XMIT_BCAST64_CX:
break;
case CMD_XMIT_SEQUENCE_CX:
case CMD_XMIT_SEQUENCE_CR:
case CMD_XMIT_SEQUENCE64_CX:
case CMD_XMIT_SEQUENCE64_CR:
case FC_TYPE_IS8802_SNAP:
break;
case FC_TYPE_FC_SERVICES:
break;
default:
"cmd=%x type=%x status=%x iotag=%x context=%x ",
iocb->ULPCONTEXT);
}
break;
case CMD_RCV_SEQUENCE_CX:
case CMD_RCV_SEQUENCE64_CX:
case CMD_RCV_SEQ64_CX:
case CMD_RCV_ELS_REQ_CX: /* Unsolicited ELS frame */
case CMD_RCV_ELS_REQ64_CX: /* Unsolicited ELS frame */
case CMD_RCV_ELS64_CX: /* Unsolicited ELS frame */
}
break;
case CMD_RCV_SEQ_LIST64_CX:
break;
case CMD_CREATE_XRI_CR:
case CMD_CREATE_XRI_CX:
break;
/* RING 2 ELS commands */
case CMD_ELS_REQUEST_CR:
case CMD_ELS_REQUEST_CX:
case CMD_XMIT_ELS_RSP_CX:
case CMD_ELS_REQUEST64_CR:
case CMD_ELS_REQUEST64_CX:
case CMD_XMIT_ELS_RSP64_CX:
break;
/* RING 3 CT commands */
case CMD_GEN_REQUEST64_CR:
case CMD_GEN_REQUEST64_CX:
#ifdef MENLO_SUPPORT
case EMLXS_MENLO_TYPE:
break;
#endif /* MENLO_SUPPORT */
case FC_TYPE_FC_SERVICES:
break;
default:
"cmd=%x type=%x status=%x iotag=%x context=%x ",
iocb->ULPCONTEXT);
}
break;
case CMD_ABORT_XRI_CN: /* Abort fcp command */
"ABORT_XRI_CN: rpi=%d iotag=%x status=%x parm=%x",
#ifdef SFCT_SUPPORT
}
#endif /* SFCT_SUPPORT */
break;
case CMD_ABORT_XRI_CX: /* Abort command */
"ABORT_XRI_CX: rpi=%d iotag=%x status=%x parm=%x sbp=%p",
#ifdef SFCT_SUPPORT
}
#endif /* SFCT_SUPPORT */
break;
case CMD_XRI_ABORTED_CX: /* Handle ABORT condition */
"XRI_ABORTED_CX: rpi=%d iotag=%x status=%x parm=%x",
#ifdef SFCT_SUPPORT
}
#endif /* SFCT_SUPPORT */
break;
case CMD_CLOSE_XRI_CN: /* Handle CLOSE condition */
"CLOSE_XRI_CN: rpi=%d iotag=%x status=%x parm=%x",
#ifdef SFCT_SUPPORT
}
#endif /* SFCT_SUPPORT */
break;
case CMD_CLOSE_XRI_CX: /* Handle CLOSE condition */
"CLOSE_XRI_CX: rpi=%d iotag=%x status=%x parm=%x sbp=%p",
#ifdef SFCT_SUPPORT
}
#endif /* SFCT_SUPPORT */
break;
case CMD_ADAPTER_MSG:
/* Allows debug adapter firmware messages to print on host */
break;
case CMD_QUE_RING_LIST64_CN:
case CMD_QUE_RING_BUF64_CN:
break;
case CMD_ASYNC_STATUS:
break;
default:
break;
} /* switch(entry->ULPCOMMAND) */
return;
} /* emlxs_proc_channel_event() */
extern char *
{
static char buffer[32];
uint32_t i;
for (i = 0; i < count; i++) {
return (emlxs_ffstate_table[i].string);
}
}
return (buffer);
} /* emlxs_ffstate_xlate() */
extern char *
{
static char buffer[32];
uint32_t i;
for (i = 0; i < count; i++) {
return (emlxs_ring_table[i].string);
}
}
return (buffer);
} /* emlxs_ring_xlate() */
extern void
{
case 512:
value = 0;
break;
case 1024:
value = 1;
break;
case 2048:
value = 2;
break;
case 4096:
value = 3;
break;
default:
"PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
goto xlate;
}
"PCI_MAX_READ: Unable to allocate mailbox buffer.");
return;
}
"PCI_MAX_READ: Unable to update. "
"status=%x value=%d (%d bytes)",
}
} else {
if (verbose &&
"PCI_MAX_READ: Updated. %d bytes",
}
}
return;
} /* emlxs_pcix_mxr_update */
extern uint32_t
{
#define SEED 0x876EDC21
/* This key is only used currently for SBUS adapters */
return (0);
}
return (0);
}
return (theKey);
} /* emlxs_get_key() */
extern void
{
uint32_t i;
/* Display firmware library one time */
for (i = 0; i < emlxs_fw_count; i++) {
emlxs_fw_table[i].label);
}
return;
} /* emlxs_fw_show() */
#ifdef MODFW_SUPPORT
extern void
{
int (*emlxs_fw_get)(emlxs_firmware_t *);
int err;
/* Make sure image is unloaded and image buffer pointer is clear */
err = 0;
hba->fw_modhandle =
if (!hba->fw_modhandle) {
"Unable to load firmware module. error=%d", err);
return;
} else {
"Firmware module loaded.");
}
err = 0;
if ((void *)emlxs_fw_get == NULL) {
"emlxs_fw_get not present. error=%d", err);
return;
}
if (emlxs_fw_get(fw)) {
return;
}
return;
} /* emlxs_fw_load() */
extern void
{
/* Clear the firmware image */
if (hba->fw_modhandle) {
/* Close the module */
"Firmware module unloaded.");
}
return;
} /* emlxs_fw_unload() */
#endif /* MODFW_SUPPORT */