From: Xiang Chen chenxiang66@hisilicon.com
For those works from event queue, if executing them such as PORTE_BROADCAST_RCVD when sas host is suspended, it will resume sas host firstly as SMP IOs are sent in the process. So phyup will occur and it will call work PORTE_BYTES_DMAED. But the original work (such as PORTE_BROADCAST_RCVD) and the work PORTE_BYTES_DMAED are in the same singlethread workqueue, so the complete of original work waits for the complete of work PORTE_BYTES_DMAED while the complete of work PORTE_BYTES_DMAED wait for the complete of original and it is blocked.
So call pm_runtime_get_noresume() to keep sas host active until finished those works.
Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Reviewed-by: John Garry john.garry@huawei.com --- drivers/scsi/libsas/sas_event.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 66eab7694832..a5b4f9435ba6 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -50,8 +50,10 @@ void sas_queue_deferred_work(struct sas_ha_struct *ha) list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { list_del_init(&sw->drain_node); ret = sas_queue_work(ha, sw); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(to_asd_sas_event(&sw->work)); + } } spin_unlock_irq(&ha->lock); } @@ -126,16 +128,22 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) static void sas_port_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha;
sas_port_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); }
static void sas_phy_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha;
sas_phy_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); }
@@ -170,14 +178,19 @@ int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, if (!ev) return -ENOMEM;
+ /* Call pm_runtime_put() with pairs in sas_port_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
if (sas_defer_event(phy, ev)) return 0;
ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + }
return ret; } @@ -196,14 +209,19 @@ int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, if (!ev) return -ENOMEM;
+ /* Call pm_runtime_put() with pairs in sas_phy_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
if (sas_defer_event(phy, ev)) return 0;
ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + }
return ret; }