aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/libsas/sas_init.c33
-rw-r--r--drivers/scsi/libsas/sas_phy.c27
-rw-r--r--include/scsi/libsas.h6
3 files changed, 64 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};
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ee1b25299dd6..de8f043475c2 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -75,6 +75,7 @@ enum phy_event {
75 PHYE_OOB_ERROR, 75 PHYE_OOB_ERROR,
76 PHYE_SPINUP_HOLD, /* hot plug SATA, no COMWAKE sent */ 76 PHYE_SPINUP_HOLD, /* hot plug SATA, no COMWAKE sent */
77 PHYE_RESUME_TIMEOUT, 77 PHYE_RESUME_TIMEOUT,
78 PHYE_SHUTDOWN,
78 PHY_NUM_EVENTS, 79 PHY_NUM_EVENTS,
79}; 80};
80 81
@@ -311,12 +312,15 @@ static inline void INIT_SAS_EVENT(struct asd_sas_event *ev,
311 ev->event = event; 312 ev->event = event;
312} 313}
313 314
315#define SAS_PHY_SHUTDOWN_THRES 1024
314 316
315/* The phy pretty much is controlled by the LLDD. 317/* The phy pretty much is controlled by the LLDD.
316 * The class only reads those fields. 318 * The class only reads those fields.
317 */ 319 */
318struct asd_sas_phy { 320struct asd_sas_phy {
319/* private: */ 321/* private: */
322 atomic_t event_nr;
323 int in_shutdown;
320 int error; 324 int error;
321 int suspended; 325 int suspended;
322 326
@@ -404,6 +408,8 @@ struct sas_ha_struct {
404 408
405 struct list_head eh_done_q; /* complete via scsi_eh_flush_done_q */ 409 struct list_head eh_done_q; /* complete via scsi_eh_flush_done_q */
406 struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */ 410 struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */
411
412 int event_thres;
407}; 413};
408 414
409#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata) 415#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)