aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorJason Yan <yanaijie@huawei.com>2017-12-08 04:42:05 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2018-01-08 21:59:28 -0500
commitf12486e06ae87453530f00a6cb49b60ae3fe4551 (patch)
tree831a4dd957ced9acdff2349e03ae84fcaacad88e /drivers/scsi/libsas
parent1c393b970e0f4070e4376d45f89a2d19a5c895d0 (diff)
scsi: libsas: shut down the PHY if events reached the threshold
If the PHY burst too many events, we will alloc a lot of events for the worker. This may leads to memory exhaustion. Dan Williams suggested to shut down the PHY if the events reached the threshold, because in this case the PHY may have gone into some erroneous state. Users can re-enable the PHY by sysfs if they want. We cannot use the fixed memory pool because if we run out of events, the shut down event and loss of signal event will lost too. The events still need to be allocated and processed in this case. Suggested-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Jason Yan <yanaijie@huawei.com> CC: John Garry <john.garry@huawei.com> CC: Johannes Thumshirn <jthumshirn@suse.de> CC: Ewan Milne <emilne@redhat.com> CC: Christoph Hellwig <hch@lst.de> CC: Tomas Henzl <thenzl@redhat.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_init.c33
-rw-r--r--drivers/scsi/libsas/sas_phy.c27
2 files changed, 58 insertions, 2 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index e04f6d6f5aff..22bfc025ae81 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -123,6 +123,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
123 INIT_LIST_HEAD(&sas_ha->defer_q); 123 INIT_LIST_HEAD(&sas_ha->defer_q);
124 INIT_LIST_HEAD(&sas_ha->eh_dev_q); 124 INIT_LIST_HEAD(&sas_ha->eh_dev_q);
125 125
126 sas_ha->event_thres = SAS_PHY_SHUTDOWN_THRES;
127
126 error = sas_register_phys(sas_ha); 128 error = sas_register_phys(sas_ha);
127 if (error) { 129 if (error) {
128 printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); 130 printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
@@ -557,14 +559,43 @@ EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
557 559
558struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy) 560struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy)
559{ 561{
562 struct asd_sas_event *event;
560 gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; 563 gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
564 struct sas_ha_struct *sas_ha = phy->ha;
565 struct sas_internal *i =
566 to_sas_internal(sas_ha->core.shost->transportt);
567
568 event = kmem_cache_zalloc(sas_event_cache, flags);
569 if (!event)
570 return NULL;
561 571
562 return kmem_cache_zalloc(sas_event_cache, flags); 572 atomic_inc(&phy->event_nr);
573
574 if (atomic_read(&phy->event_nr) > phy->ha->event_thres) {
575 if (i->dft->lldd_control_phy) {
576 if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) {
577 sas_printk("The phy%02d bursting events, shut it down.\n",
578 phy->id);
579 sas_notify_phy_event(phy, PHYE_SHUTDOWN);
580 }
581 } else {
582 /* Do not support PHY control, stop allocating events */
583 WARN_ONCE(1, "PHY control not supported.\n");
584 kmem_cache_free(sas_event_cache, event);
585 atomic_dec(&phy->event_nr);
586 event = NULL;
587 }
588 }
589
590 return event;
563} 591}
564 592
565void sas_free_event(struct asd_sas_event *event) 593void sas_free_event(struct asd_sas_event *event)
566{ 594{
595 struct asd_sas_phy *phy = event->phy;
596
567 kmem_cache_free(sas_event_cache, event); 597 kmem_cache_free(sas_event_cache, event);
598 atomic_dec(&phy->event_nr);
568} 599}
569 600
570/* ---------- SAS Class register/unregister ---------- */ 601/* ---------- SAS Class register/unregister ---------- */
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 59f82929b0a3..bf3e1b979ca6 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -35,6 +35,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
35 struct asd_sas_event *ev = to_asd_sas_event(work); 35 struct asd_sas_event *ev = to_asd_sas_event(work);
36 struct asd_sas_phy *phy = ev->phy; 36 struct asd_sas_phy *phy = ev->phy;
37 37
38 phy->in_shutdown = 0;
38 phy->error = 0; 39 phy->error = 0;
39 sas_deform_port(phy, 1); 40 sas_deform_port(phy, 1);
40} 41}
@@ -44,6 +45,7 @@ static void sas_phye_oob_done(struct work_struct *work)
44 struct asd_sas_event *ev = to_asd_sas_event(work); 45 struct asd_sas_event *ev = to_asd_sas_event(work);
45 struct asd_sas_phy *phy = ev->phy; 46 struct asd_sas_phy *phy = ev->phy;
46 47
48 phy->in_shutdown = 0;
47 phy->error = 0; 49 phy->error = 0;
48} 50}
49 51
@@ -105,6 +107,28 @@ static void sas_phye_resume_timeout(struct work_struct *work)
105} 107}
106 108
107 109
110static void sas_phye_shutdown(struct work_struct *work)
111{
112 struct asd_sas_event *ev = to_asd_sas_event(work);
113 struct asd_sas_phy *phy = ev->phy;
114 struct sas_ha_struct *sas_ha = phy->ha;
115 struct sas_internal *i =
116 to_sas_internal(sas_ha->core.shost->transportt);
117
118 if (phy->enabled) {
119 int ret;
120
121 phy->error = 0;
122 phy->enabled = 0;
123 ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
124 if (ret)
125 sas_printk("lldd disable phy%02d returned %d\n",
126 phy->id, ret);
127 } else
128 sas_printk("phy%02d is not enabled, cannot shutdown\n",
129 phy->id);
130}
131
108/* ---------- Phy class registration ---------- */ 132/* ---------- Phy class registration ---------- */
109 133
110int sas_register_phys(struct sas_ha_struct *sas_ha) 134int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -116,6 +140,7 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
116 struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 140 struct asd_sas_phy *phy = sas_ha->sas_phy[i];
117 141
118 phy->error = 0; 142 phy->error = 0;
143 atomic_set(&phy->event_nr, 0);
119 INIT_LIST_HEAD(&phy->port_phy_el); 144 INIT_LIST_HEAD(&phy->port_phy_el);
120 145
121 phy->port = NULL; 146 phy->port = NULL;
@@ -151,5 +176,5 @@ const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
151 [PHYE_OOB_ERROR] = sas_phye_oob_error, 176 [PHYE_OOB_ERROR] = sas_phye_oob_error,
152 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, 177 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
153 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout, 178 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
154 179 [PHYE_SHUTDOWN] = sas_phye_shutdown,
155}; 180};