ibmvnic: Introduce hard reset recovery
Introduce a recovery hard reset to handle reset failure as a result of change of device context following a transport event, such as a backing device failover or partition migration. These operations reset the device context to its initial state. If this occurs during a reset, any initialization commands are likely to fail with an invalid state error as backing device firmware requests reinitialization. When this happens, make one more attempt by performing a hard reset, which frees any resources currently allocated and performs device initialization. If a transport event occurs during a device reset, a flag is set which will trigger a new hard reset following the completionof the current reset event. Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
06e43d7f9f
Коммит
2770a7984d
|
@ -1878,6 +1878,85 @@ static int do_reset(struct ibmvnic_adapter *adapter,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_hard_reset(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_rwi *rwi, u32 reset_state)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int rc;
|
||||
|
||||
netdev_dbg(adapter->netdev, "Hard resetting driver (%d)\n",
|
||||
rwi->reset_reason);
|
||||
|
||||
netif_carrier_off(netdev);
|
||||
adapter->reset_reason = rwi->reset_reason;
|
||||
|
||||
ibmvnic_cleanup(netdev);
|
||||
release_resources(adapter);
|
||||
release_sub_crqs(adapter, 0);
|
||||
release_crq_queue(adapter);
|
||||
|
||||
/* remove the closed state so when we call open it appears
|
||||
* we are coming from the probed state.
|
||||
*/
|
||||
adapter->state = VNIC_PROBED;
|
||||
|
||||
rc = init_crq_queue(adapter);
|
||||
if (rc) {
|
||||
netdev_err(adapter->netdev,
|
||||
"Couldn't initialize crq. rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ibmvnic_init(adapter);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If the adapter was in PROBE state prior to the reset,
|
||||
* exit here.
|
||||
*/
|
||||
if (reset_state == VNIC_PROBED)
|
||||
return 0;
|
||||
|
||||
rc = ibmvnic_login(netdev);
|
||||
if (rc) {
|
||||
adapter->state = VNIC_PROBED;
|
||||
return 0;
|
||||
}
|
||||
/* netif_set_real_num_xx_queues needs to take rtnl lock here
|
||||
* unless wait_for_reset is set, in which case the rtnl lock
|
||||
* has already been taken before initializing the reset
|
||||
*/
|
||||
if (!adapter->wait_for_reset) {
|
||||
rtnl_lock();
|
||||
rc = init_resources(adapter);
|
||||
rtnl_unlock();
|
||||
} else {
|
||||
rc = init_resources(adapter);
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ibmvnic_disable_irqs(adapter);
|
||||
adapter->state = VNIC_CLOSED;
|
||||
|
||||
if (reset_state == VNIC_CLOSED)
|
||||
return 0;
|
||||
|
||||
rc = __ibmvnic_open(netdev);
|
||||
if (rc) {
|
||||
if (list_empty(&adapter->rwi_list))
|
||||
adapter->state = VNIC_CLOSED;
|
||||
else
|
||||
adapter->state = reset_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
netif_carrier_on(netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct ibmvnic_rwi *rwi;
|
||||
|
@ -1923,9 +2002,15 @@ static void __ibmvnic_reset(struct work_struct *work)
|
|||
|
||||
rwi = get_next_rwi(adapter);
|
||||
while (rwi) {
|
||||
rc = do_reset(adapter, rwi, reset_state);
|
||||
if (adapter->force_reset_recovery) {
|
||||
adapter->force_reset_recovery = false;
|
||||
rc = do_hard_reset(adapter, rwi, reset_state);
|
||||
} else {
|
||||
rc = do_reset(adapter, rwi, reset_state);
|
||||
}
|
||||
kfree(rwi);
|
||||
if (rc && rc != IBMVNIC_INIT_FAILED)
|
||||
if (rc && rc != IBMVNIC_INIT_FAILED &&
|
||||
!adapter->force_reset_recovery)
|
||||
break;
|
||||
|
||||
rwi = get_next_rwi(adapter);
|
||||
|
@ -1951,9 +2036,9 @@ static void __ibmvnic_reset(struct work_struct *work)
|
|||
static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
|
||||
enum ibmvnic_reset_reason reason)
|
||||
{
|
||||
struct list_head *entry, *tmp_entry;
|
||||
struct ibmvnic_rwi *rwi, *tmp;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct list_head *entry;
|
||||
int ret;
|
||||
|
||||
if (adapter->state == VNIC_REMOVING ||
|
||||
|
@ -1989,7 +2074,13 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
|
|||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* if we just received a transport event,
|
||||
* flush reset queue and process this reset
|
||||
*/
|
||||
if (adapter->force_reset_recovery && !list_empty(&adapter->rwi_list)) {
|
||||
list_for_each_safe(entry, tmp_entry, &adapter->rwi_list)
|
||||
list_del(entry);
|
||||
}
|
||||
rwi->reset_reason = reason;
|
||||
list_add_tail(&rwi->list, &adapter->rwi_list);
|
||||
mutex_unlock(&adapter->rwi_lock);
|
||||
|
@ -4271,6 +4362,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
|
|||
case IBMVNIC_CRQ_XPORT_EVENT:
|
||||
netif_carrier_off(netdev);
|
||||
adapter->crq.active = false;
|
||||
if (adapter->resetting)
|
||||
adapter->force_reset_recovery = true;
|
||||
if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
|
||||
dev_info(dev, "Migrated, re-enabling adapter\n");
|
||||
ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
|
||||
|
|
|
@ -1109,6 +1109,7 @@ struct ibmvnic_adapter {
|
|||
|
||||
bool mac_change_pending;
|
||||
bool failover_pending;
|
||||
bool force_reset_recovery;
|
||||
|
||||
struct ibmvnic_tunables desired;
|
||||
struct ibmvnic_tunables fallback;
|
||||
|
|
Загрузка…
Ссылка в новой задаче