INIT_LIST_HEAD(&sas_ha->defer_q);
        INIT_LIST_HEAD(&sas_ha->eh_dev_q);
 
+       sas_ha->event_thres = SAS_PHY_SHUTDOWN_THRES;
+
        error = sas_register_phys(sas_ha);
        if (error) {
                printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
 
 struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy)
 {
+       struct asd_sas_event *event;
        gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+       struct sas_ha_struct *sas_ha = phy->ha;
+       struct sas_internal *i =
+               to_sas_internal(sas_ha->core.shost->transportt);
+
+       event = kmem_cache_zalloc(sas_event_cache, flags);
+       if (!event)
+               return NULL;
 
-       return kmem_cache_zalloc(sas_event_cache, flags);
+       atomic_inc(&phy->event_nr);
+
+       if (atomic_read(&phy->event_nr) > phy->ha->event_thres) {
+               if (i->dft->lldd_control_phy) {
+                       if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) {
+                               sas_printk("The phy%02d bursting events, shut it down.\n",
+                                       phy->id);
+                               sas_notify_phy_event(phy, PHYE_SHUTDOWN);
+                       }
+               } else {
+                       /* Do not support PHY control, stop allocating events */
+                       WARN_ONCE(1, "PHY control not supported.\n");
+                       kmem_cache_free(sas_event_cache, event);
+                       atomic_dec(&phy->event_nr);
+                       event = NULL;
+               }
+       }
+
+       return event;
 }
 
 void sas_free_event(struct asd_sas_event *event)
 {
+       struct asd_sas_phy *phy = event->phy;
+
        kmem_cache_free(sas_event_cache, event);
+       atomic_dec(&phy->event_nr);
 }
 
 /* ---------- SAS Class register/unregister ---------- */
 
        struct asd_sas_event *ev = to_asd_sas_event(work);
        struct asd_sas_phy *phy = ev->phy;
 
+       phy->in_shutdown = 0;
        phy->error = 0;
        sas_deform_port(phy, 1);
 }
        struct asd_sas_event *ev = to_asd_sas_event(work);
        struct asd_sas_phy *phy = ev->phy;
 
+       phy->in_shutdown = 0;
        phy->error = 0;
 }
 
 }
 
 
+static void sas_phye_shutdown(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 *sas_ha = phy->ha;
+       struct sas_internal *i =
+               to_sas_internal(sas_ha->core.shost->transportt);
+
+       if (phy->enabled) {
+               int ret;
+
+               phy->error = 0;
+               phy->enabled = 0;
+               ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
+               if (ret)
+                       sas_printk("lldd disable phy%02d returned %d\n",
+                               phy->id, ret);
+       } else
+               sas_printk("phy%02d is not enabled, cannot shutdown\n",
+                       phy->id);
+}
+
 /* ---------- Phy class registration ---------- */
 
 int sas_register_phys(struct sas_ha_struct *sas_ha)
                struct asd_sas_phy *phy = sas_ha->sas_phy[i];
 
                phy->error = 0;
+               atomic_set(&phy->event_nr, 0);
                INIT_LIST_HEAD(&phy->port_phy_el);
 
                phy->port = NULL;
        [PHYE_OOB_ERROR] = sas_phye_oob_error,
        [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
        [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
-
+       [PHYE_SHUTDOWN] = sas_phye_shutdown,
 };
 
        PHYE_OOB_ERROR,
        PHYE_SPINUP_HOLD,             /* hot plug SATA, no COMWAKE sent */
        PHYE_RESUME_TIMEOUT,
+       PHYE_SHUTDOWN,
        PHY_NUM_EVENTS,
 };
 
        ev->event = event;
 }
 
+#define SAS_PHY_SHUTDOWN_THRES   1024
 
 /* The phy pretty much is controlled by the LLDD.
  * The class only reads those fields.
  */
 struct asd_sas_phy {
 /* private: */
+       atomic_t event_nr;
+       int in_shutdown;
        int error;
        int suspended;
 
 
        struct list_head eh_done_q;  /* complete via scsi_eh_flush_done_q */
        struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */
+
+       int event_thres;
 };
 
 #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)