aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c')
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c138
1 files changed, 109 insertions, 29 deletions
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 7dd9a4b107e6..65a718f9ccd3 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -82,7 +82,6 @@ static void netxen_create_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_create_diag_entries(struct netxen_adapter *adapter);
static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
-
static int nx_dev_request_aer(struct netxen_adapter *adapter);
static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
static int netxen_can_start_firmware(struct netxen_adapter *adapter);
@@ -519,7 +518,7 @@ static int netxen_nic_set_mac(struct net_device *netdev, void *p)
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
- return -EINVAL;
+ return -EADDRNOTAVAIL;
if (netif_running(netdev)) {
netif_device_detach(netdev);
@@ -802,16 +801,16 @@ err_out:
static void
netxen_check_options(struct netxen_adapter *adapter)
{
- u32 fw_major, fw_minor, fw_build;
+ u32 fw_major, fw_minor, fw_build, prev_fw_version;
char brd_name[NETXEN_MAX_SHORT_NAME];
char serial_num[32];
- int i, offset, val;
- int *ptr32;
+ int i, offset, val, err;
+ __le32 *ptr32;
struct pci_dev *pdev = adapter->pdev;
adapter->driver_mismatch = 0;
- ptr32 = (int *)&serial_num;
+ ptr32 = (__le32 *)&serial_num;
offset = NX_FW_SERIAL_NUM_OFFSET;
for (i = 0; i < 8; i++) {
if (netxen_rom_fast_read(adapter, offset, &val) == -1) {
@@ -826,9 +825,22 @@ netxen_check_options(struct netxen_adapter *adapter)
fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
-
+ prev_fw_version = adapter->fw_version;
adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
+ /* Get FW Mini Coredump template and store it */
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ if (adapter->mdump.md_template == NULL ||
+ adapter->fw_version > prev_fw_version) {
+ kfree(adapter->mdump.md_template);
+ adapter->mdump.md_template = NULL;
+ err = netxen_setup_minidump(adapter);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "Failed to setup minidump rcode = %d\n", err);
+ }
+ }
+
if (adapter->portnum == 0) {
get_brd_name_by_type(adapter->ahw.board_type, brd_name);
@@ -909,7 +921,12 @@ netxen_start_firmware(struct netxen_adapter *adapter)
if (err)
return err;
- if (!netxen_can_start_firmware(adapter))
+ err = netxen_can_start_firmware(adapter);
+
+ if (err < 0)
+ return err;
+
+ if (!err)
goto wait_init;
first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc));
@@ -1403,7 +1420,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev = alloc_etherdev(sizeof(struct netxen_adapter));
if(!netdev) {
- dev_err(&pdev->dev, "failed to allocate net_device\n");
err = -ENOMEM;
goto err_out_free_res;
}
@@ -1529,6 +1545,18 @@ err_out_disable_pdev:
return err;
}
+static
+void netxen_cleanup_minidump(struct netxen_adapter *adapter)
+{
+ kfree(adapter->mdump.md_template);
+ adapter->mdump.md_template = NULL;
+
+ if (adapter->mdump.md_capture_buff) {
+ vfree(adapter->mdump.md_capture_buff);
+ adapter->mdump.md_capture_buff = NULL;
+ }
+}
+
static void __devexit netxen_nic_remove(struct pci_dev *pdev)
{
struct netxen_adapter *adapter;
@@ -1564,8 +1592,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_release_firmware(adapter);
- if (NX_IS_REVISION_P3(pdev->revision))
+ if (NX_IS_REVISION_P3(pdev->revision)) {
+ netxen_cleanup_minidump(adapter);
pci_disable_pcie_error_reporting(pdev);
+ }
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2317,7 +2347,7 @@ nx_incr_dev_ref_cnt(struct netxen_adapter *adapter)
static int
nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
{
- int count;
+ int count, state;
if (netxen_api_lock(adapter))
return -EIO;
@@ -2325,8 +2355,9 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
WARN_ON(count == 0);
NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
+ state = NXRD32(adapter, NX_CRB_DEV_STATE);
- if (count == 0)
+ if (count == 0 && state != NX_DEV_FAILED)
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
netxen_api_unlock(adapter);
@@ -2355,7 +2386,7 @@ nx_dev_request_aer(struct netxen_adapter *adapter)
return ret;
}
-static int
+int
nx_dev_request_reset(struct netxen_adapter *adapter)
{
u32 state;
@@ -2366,10 +2397,11 @@ nx_dev_request_reset(struct netxen_adapter *adapter)
state = NXRD32(adapter, NX_CRB_DEV_STATE);
- if (state == NX_DEV_NEED_RESET)
+ if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED)
ret = 0;
else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) {
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET);
+ adapter->flags |= NETXEN_FW_RESET_OWNER;
ret = 0;
}
@@ -2384,8 +2416,10 @@ netxen_can_start_firmware(struct netxen_adapter *adapter)
int count;
int can_start = 0;
- if (netxen_api_lock(adapter))
- return 0;
+ if (netxen_api_lock(adapter)) {
+ nx_incr_dev_ref_cnt(adapter);
+ return -1;
+ }
count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
@@ -2457,8 +2491,31 @@ netxen_fwinit_work(struct work_struct *work)
struct netxen_adapter *adapter = container_of(work,
struct netxen_adapter, fw_work.work);
int dev_state;
-
+ int count;
dev_state = NXRD32(adapter, NX_CRB_DEV_STATE);
+ if (adapter->flags & NETXEN_FW_RESET_OWNER) {
+ count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
+ WARN_ON(count == 0);
+ if (count == 1) {
+ if (adapter->mdump.md_enabled) {
+ rtnl_lock();
+ netxen_dump_fw(adapter);
+ rtnl_unlock();
+ }
+ adapter->flags &= ~NETXEN_FW_RESET_OWNER;
+ if (netxen_api_lock(adapter)) {
+ clear_bit(__NX_RESETTING, &adapter->state);
+ NXWR32(adapter, NX_CRB_DEV_STATE,
+ NX_DEV_FAILED);
+ return;
+ }
+ count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
+ NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
+ NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
+ dev_state = NX_DEV_COLD;
+ netxen_api_unlock(adapter);
+ }
+ }
switch (dev_state) {
case NX_DEV_COLD:
@@ -2471,11 +2528,9 @@ netxen_fwinit_work(struct work_struct *work)
case NX_DEV_NEED_RESET:
case NX_DEV_INITALIZING:
- if (++adapter->fw_wait_cnt < FW_POLL_THRESH) {
netxen_schedule_work(adapter,
netxen_fwinit_work, 2 * FW_POLL_DELAY);
return;
- }
case NX_DEV_FAILED:
default:
@@ -2483,6 +2538,15 @@ netxen_fwinit_work(struct work_struct *work)
break;
}
+ if (netxen_api_lock(adapter)) {
+ clear_bit(__NX_RESETTING, &adapter->state);
+ return;
+ }
+ NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_FAILED);
+ netxen_api_unlock(adapter);
+ dev_err(&adapter->pdev->dev, "%s: Device initialization Failed\n",
+ adapter->netdev->name);
+
clear_bit(__NX_RESETTING, &adapter->state);
}
@@ -2492,7 +2556,7 @@ netxen_detach_work(struct work_struct *work)
struct netxen_adapter *adapter = container_of(work,
struct netxen_adapter, fw_work.work);
struct net_device *netdev = adapter->netdev;
- int ref_cnt, delay;
+ int ref_cnt = 0, delay;
u32 status;
netif_device_detach(netdev);
@@ -2511,7 +2575,8 @@ netxen_detach_work(struct work_struct *work)
if (adapter->temp == NX_TEMP_PANIC)
goto err_ret;
- ref_cnt = nx_decr_dev_ref_cnt(adapter);
+ if (!(adapter->flags & NETXEN_FW_RESET_OWNER))
+ ref_cnt = nx_decr_dev_ref_cnt(adapter);
if (ref_cnt == -EIO)
goto err_ret;
@@ -2531,6 +2596,7 @@ static int
netxen_check_health(struct netxen_adapter *adapter)
{
u32 state, heartbit;
+ u32 peg_status;
struct net_device *netdev = adapter->netdev;
state = NXRD32(adapter, NX_CRB_DEV_STATE);
@@ -2551,7 +2617,7 @@ netxen_check_health(struct netxen_adapter *adapter)
* Send request to destroy context in case of tx timeout only
* and doesn't required in case of Fw hang
*/
- if (state == NX_DEV_NEED_RESET) {
+ if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED) {
adapter->need_fw_reset = 1;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
goto detach;
@@ -2577,8 +2643,24 @@ netxen_check_health(struct netxen_adapter *adapter)
clear_bit(__NX_FW_ATTACHED, &adapter->state);
- dev_info(&netdev->dev, "firmware hang detected\n");
-
+ dev_err(&netdev->dev, "firmware hang detected\n");
+ peg_status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1);
+ dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
+ "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+ "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+ "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+ "PEG_NET_4_PC: 0x%x\n",
+ peg_status,
+ NXRD32(adapter, NETXEN_PEG_HALT_STATUS2),
+ NXRD32(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c),
+ NXRD32(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c),
+ NXRD32(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c),
+ NXRD32(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c),
+ NXRD32(adapter, NETXEN_CRB_PEG_NET_4 + 0x3c));
+ if (NX_FWERROR_PEGSTAT1(peg_status) == 0x67)
+ dev_err(&adapter->pdev->dev,
+ "Firmware aborted with error code 0x00006700. "
+ "Device is being reset.\n");
detach:
if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
!test_and_set_bit(__NX_RESETTING, &adapter->state))
@@ -2848,13 +2930,12 @@ static struct bin_attribute bin_attr_mem = {
static void
netxen_create_sysfs_entries(struct netxen_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
- struct device *dev = &netdev->dev;
+ struct device *dev = &adapter->pdev->dev;
if (adapter->capabilities & NX_FW_CAPABILITY_BDG) {
/* bridged_mode control */
if (device_create_file(dev, &dev_attr_bridged_mode)) {
- dev_warn(&netdev->dev,
+ dev_warn(dev,
"failed to create bridged_mode sysfs entry\n");
}
}
@@ -2863,8 +2944,7 @@ netxen_create_sysfs_entries(struct netxen_adapter *adapter)
static void
netxen_remove_sysfs_entries(struct netxen_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
- struct device *dev = &netdev->dev;
+ struct device *dev = &adapter->pdev->dev;
if (adapter->capabilities & NX_FW_CAPABILITY_BDG)
device_remove_file(dev, &dev_attr_bridged_mode);