125184Sjkh// SPDX-License-Identifier: GPL-2.0 225184Sjkh/* 342621Shm * Serial Attached SCSI (SAS) Event processing 425184Sjkh * 525184Sjkh * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 625184Sjkh * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 725184Sjkh */ 825184Sjkh 925184Sjkh#include <linux/export.h> 1025184Sjkh#include <scsi/scsi_host.h> 1125184Sjkh#include "sas_internal.h" 1225184Sjkh 1325184Sjkhbool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 1425184Sjkh{ 1525184Sjkh if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 1625184Sjkh return false; 1725184Sjkh 1825184Sjkh if (test_bit(SAS_HA_DRAINING, &ha->state)) { 1925184Sjkh /* add it to the defer list, if not already pending */ 2025184Sjkh if (list_empty(&sw->drain_node)) 2125184Sjkh list_add_tail(&sw->drain_node, &ha->defer_q); 2225184Sjkh return true; 2325184Sjkh } 2425184Sjkh 2525184Sjkh return queue_work(ha->event_q, &sw->work); 2625184Sjkh} 2725184Sjkh 2840006Sphkstatic bool sas_queue_event(int event, struct sas_work *work, 2940006Sphk struct sas_ha_struct *ha) 3040006Sphk{ 3140006Sphk unsigned long flags; 3240006Sphk bool rc; 3340006Sphk 3442621Shm spin_lock_irqsave(&ha->lock, flags); 3542621Shm rc = sas_queue_work(ha, work); 3642621Shm spin_unlock_irqrestore(&ha->lock, flags); 3742621Shm 3842621Shm return rc; 3925184Sjkh} 4025184Sjkh 4125184Sjkhvoid sas_queue_deferred_work(struct sas_ha_struct *ha) 4233682Sbrian{ 4325184Sjkh struct sas_work *sw, *_sw; 4425184Sjkh 4525184Sjkh spin_lock_irq(&ha->lock); 4625184Sjkh list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { 4725184Sjkh list_del_init(&sw->drain_node); 4825184Sjkh 4925184Sjkh if (!sas_queue_work(ha, sw)) { 5025184Sjkh pm_runtime_put(ha->dev); 5125184Sjkh sas_free_event(to_asd_sas_event(&sw->work)); 5225184Sjkh } 5325184Sjkh } 5425184Sjkh spin_unlock_irq(&ha->lock); 5525184Sjkh} 5625184Sjkh 5725184Sjkhvoid __sas_drain_work(struct sas_ha_struct *ha) 5825184Sjkh{ 5925184Sjkh set_bit(SAS_HA_DRAINING, &ha->state); 6025184Sjkh /* flush submitters */ 6125184Sjkh spin_lock_irq(&ha->lock); 6225184Sjkh spin_unlock_irq(&ha->lock); 6325184Sjkh 6425184Sjkh drain_workqueue(ha->event_q); 6525184Sjkh drain_workqueue(ha->disco_q); 6625184Sjkh 6725184Sjkh clear_bit(SAS_HA_DRAINING, &ha->state); 6829300Sdanny sas_queue_deferred_work(ha); 6929300Sdanny} 7029300Sdanny 7129300Sdannyint sas_drain_work(struct sas_ha_struct *ha) 7232382Salex{ 7332382Salex int err; 7432382Salex 7529300Sdanny err = mutex_lock_interruptible(&ha->drain_mutex); 7629300Sdanny if (err) 7729300Sdanny return err; 7829300Sdanny if (test_bit(SAS_HA_REGISTERED, &ha->state)) 7941077Speter __sas_drain_work(ha); 8029300Sdanny mutex_unlock(&ha->drain_mutex); 8129300Sdanny 8229300Sdanny return 0; 8329300Sdanny} 8429300SdannyEXPORT_SYMBOL_GPL(sas_drain_work); 8529300Sdanny 8629300Sdannyvoid sas_disable_revalidation(struct sas_ha_struct *ha) 8729300Sdanny{ 8829300Sdanny mutex_lock(&ha->disco_mutex); 8929300Sdanny set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); 9029300Sdanny mutex_unlock(&ha->disco_mutex); 9125364Sjkh} 9229300Sdanny 9329300Sdannyvoid sas_enable_revalidation(struct sas_ha_struct *ha) 9433337Salex{ 9533337Salex int i; 9633149Salex 9733149Salex mutex_lock(&ha->disco_mutex); 9833149Salex clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); 9933149Salex for (i = 0; i < ha->num_phys; i++) { 10029300Sdanny struct asd_sas_port *port = ha->sas_port[i]; 10125184Sjkh const int ev = DISCE_REVALIDATE_DOMAIN; 10225184Sjkh struct sas_discovery *d = &port->disc; 10340006Sphk struct asd_sas_phy *sas_phy; 10440006Sphk 10540006Sphk if (!test_and_clear_bit(ev, &d->pending)) 10640006Sphk continue; 10740006Sphk 10829300Sdanny spin_lock(&port->phy_list_lock); 10929300Sdanny if (list_empty(&port->phy_list)) { 11025184Sjkh spin_unlock(&port->phy_list_lock); 11125184Sjkh continue; 11225184Sjkh } 11325184Sjkh 11425184Sjkh sas_phy = container_of(port->phy_list.next, struct asd_sas_phy, 11525184Sjkh port_phy_el); 11625184Sjkh spin_unlock(&port->phy_list_lock); 11725184Sjkh sas_notify_port_event(sas_phy, 11825184Sjkh PORTE_BROADCAST_RCVD, GFP_KERNEL); 11925184Sjkh } 12025184Sjkh mutex_unlock(&ha->disco_mutex); 12125184Sjkh} 12225184Sjkh 12325184Sjkh 12427218Spststatic void sas_port_event_worker(struct work_struct *work) 12527218Spst{ 12627218Spst struct asd_sas_event *ev = to_asd_sas_event(work); 12727218Spst struct asd_sas_phy *phy = ev->phy; 12827218Spst struct sas_ha_struct *ha = phy->ha; 12939267Sjkoshy 13039267Sjkoshy sas_port_event_fns[ev->event](work); 13139267Sjkoshy pm_runtime_put(ha->dev); 13239267Sjkoshy sas_free_event(ev); 13339267Sjkoshy} 13425184Sjkh 13525365Sjkhstatic void sas_phy_event_worker(struct work_struct *work) 13625184Sjkh{ 13725184Sjkh struct asd_sas_event *ev = to_asd_sas_event(work); 13825184Sjkh struct asd_sas_phy *phy = ev->phy; 13933439Sguido struct sas_ha_struct *ha = phy->ha; 14033439Sguido 14133439Sguido sas_phy_event_fns[ev->event](work); 14233439Sguido pm_runtime_put(ha->dev); 14333439Sguido sas_free_event(ev); 14433439Sguido} 14533439Sguido 14633439Sguido/* defer works of new phys during suspend */ 14733439Sguidostatic bool sas_defer_event(struct asd_sas_phy *phy, struct asd_sas_event *ev) 14833439Sguido{ 14925184Sjkh struct sas_ha_struct *ha = phy->ha; 15025365Sjkh unsigned long flags; 15125184Sjkh bool deferred = false; 15225184Sjkh 15325184Sjkh spin_lock_irqsave(&ha->lock, flags); 15436174Sjkh if (test_bit(SAS_HA_RESUMING, &ha->state) && !phy->suspended) { 15536174Sjkh struct sas_work *sw = &ev->work; 15636174Sjkh 15736174Sjkh list_add_tail(&sw->drain_node, &ha->defer_q); 15836174Sjkh deferred = true; 15936174Sjkh } 16036174Sjkh spin_unlock_irqrestore(&ha->lock, flags); 16136174Sjkh return deferred; 16236174Sjkh} 16336174Sjkh 16436174Sjkhvoid sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, 16525184Sjkh gfp_t gfp_flags) 16636174Sjkh{ 16725184Sjkh struct sas_ha_struct *ha = phy->ha; 16825184Sjkh struct asd_sas_event *ev; 16925765Sjkh 17036174Sjkh BUG_ON(event >= PORT_NUM_EVENTS); 17136174Sjkh 17225765Sjkh ev = sas_alloc_event(phy, gfp_flags); 17336174Sjkh if (!ev) 17434395Sjkh return; 17534395Sjkh 17634395Sjkh /* Call pm_runtime_put() with pairs in sas_port_event_worker() */ 17725184Sjkh pm_runtime_get_noresume(ha->dev); 17825184Sjkh 17925184Sjkh INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event); 18025184Sjkh 18125184Sjkh if (sas_defer_event(phy, ev)) 18225184Sjkh return; 18325184Sjkh 18432949Swollman if (!sas_queue_event(event, &ev->work, ha)) { 18525184Sjkh pm_runtime_put(ha->dev); 18625184Sjkh sas_free_event(ev); 18731472Sobrien } 18835787Sandreas} 18931472SobrienEXPORT_SYMBOL_GPL(sas_notify_port_event); 19025184Sjkh 19131472Sobrienvoid sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, 19235787Sandreas gfp_t gfp_flags) 19325184Sjkh{ 19425184Sjkh struct sas_ha_struct *ha = phy->ha; 19525184Sjkh struct asd_sas_event *ev; 19625184Sjkh 19725184Sjkh BUG_ON(event >= PHY_NUM_EVENTS); 19825184Sjkh 19925184Sjkh ev = sas_alloc_event(phy, gfp_flags); 20025184Sjkh if (!ev) 20125184Sjkh return; 20225184Sjkh 20325184Sjkh /* Call pm_runtime_put() with pairs in sas_phy_event_worker() */ 20425184Sjkh pm_runtime_get_noresume(ha->dev); 20525184Sjkh 20625184Sjkh INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event); 20725184Sjkh 20825184Sjkh if (sas_defer_event(phy, ev)) 20925184Sjkh return; 21025184Sjkh 21125184Sjkh if (!sas_queue_event(event, &ev->work, ha)) { 21225184Sjkh pm_runtime_put(ha->dev); 21325184Sjkh sas_free_event(ev); 21425184Sjkh } 21525184Sjkh} 21625184SjkhEXPORT_SYMBOL_GPL(sas_notify_phy_event); 21725184Sjkh