qlcnic: fix beacon and LED test.

o Updated version number to 5.0.25

o Do not hold onto RESETTING_BIT for entire duration of LED/ beacon test.
  Instead, just checking for RESETTING_BIT not set before sending config_led
  command down to card.

o Take rtnl_lock instead of RESETTING_BIT for beacon test while sending
  config_led command down to make sure interface cannot be brought up/ down.

o Allocate and free resources if interface is down before
  sending the config_led command. This is to make sure config_led
  command sending doesn't fail.

o Clear QLCNIC_LED_ENABLE bit if beacon/ LED test fails to start.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sucheta Chakraborty 2011-10-28 12:57:15 +00:00 committed by David S. Miller
parent 445b62dfd9
commit 10ee0faed9
3 changed files with 57 additions and 31 deletions

View File

@ -36,8 +36,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
#define _QLCNIC_LINUX_SUBVERSION 24
#define QLCNIC_LINUX_VERSIONID "5.0.24"
#define _QLCNIC_LINUX_SUBVERSION 25
#define QLCNIC_LINUX_VERSIONID "5.0.25"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))

View File

@ -935,31 +935,49 @@ static int qlcnic_set_led(struct net_device *dev,
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int max_sds_rings = adapter->max_sds_rings;
int err = -EIO, active = 1;
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(dev, "LED test not supported for non "
"privilege function\n");
return -EOPNOTSUPP;
}
switch (state) {
case ETHTOOL_ID_ACTIVE:
if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
return -EBUSY;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
if (test_bit(__QLCNIC_RESETTING, &adapter->state))
break;
if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return -EIO;
}
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
break;
set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
}
if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
return 0;
if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
err = 0;
break;
}
dev_err(&adapter->pdev->dev,
"Failed to set LED blink state.\n");
break;
case ETHTOOL_ID_INACTIVE:
active = 0;
if (test_bit(__QLCNIC_RESETTING, &adapter->state))
break;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
break;
set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
}
if (adapter->nic_ops->config_led(adapter, 0, 0xf))
dev_err(&adapter->pdev->dev,
"Failed to reset LED blink state.\n");
@ -970,14 +988,13 @@ static int qlcnic_set_led(struct net_device *dev,
return -EINVAL;
}
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(dev, max_sds_rings);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
if (!active || err)
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
return -EIO;
return err;
}
static void

View File

@ -3504,11 +3504,16 @@ qlcnic_store_beacon(struct device *dev,
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int max_sds_rings = adapter->max_sds_rings;
int dev_down = 0;
u16 beacon;
u8 b_state, b_rate;
int err;
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
dev_warn(dev, "LED test not supported for non "
"privilege function\n");
return -EOPNOTSUPP;
}
if (len != sizeof(u16))
return QL_STATUS_INVALID_PARAM;
@ -3520,36 +3525,40 @@ qlcnic_store_beacon(struct device *dev,
if (adapter->ahw->beacon_state == b_state)
return len;
rtnl_lock();
if (!adapter->ahw->beacon_state)
if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
rtnl_unlock();
return -EBUSY;
}
if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
err = -EIO;
goto out;
}
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
if (err) {
clear_bit(__QLCNIC_RESETTING, &adapter->state);
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
return err;
}
dev_down = 1;
if (err)
goto out;
set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
}
err = qlcnic_config_led(adapter, b_state, b_rate);
if (!err) {
adapter->ahw->beacon_state = b_state;
err = len;
adapter->ahw->beacon_state = b_state;
}
if (dev_down) {
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
if (!b_state)
out:
if (!adapter->ahw->beacon_state)
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
rtnl_unlock();
return err;
}