scsi: hpsa: separate monitor events from rescan worker
authorScott Teel <scott.teel@microsemi.com>
Thu, 4 May 2017 22:51:36 +0000 (17:51 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 13 Jun 2017 00:48:01 +0000 (20:48 -0400)
create new worker thread to monitor controller events
 - both the rescan and event monitor workers can cause a rescan to occur
   however for multipath we have found that we need to respond faster
   than the normal scheduled rescan interval for path fail-overs.
 - getting controller events only involves reading a register, but the
   rescan worker can obtain an updated LUN list when there is a PTRAID
   device present.
 - move common code to a separate function.
advantages:
 - detect controller events more frequently.
 - leave rescan thread interval at 30 seconds.

Reviewed-by: Scott Benesh <scott.benesh@microsemi.com>
Reviewed-by: Scott Teel <scott.teel@microsemi.com>
Reviewed-by: Kevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: Don Brace <don.brace@microsemi.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h

index 5b0cc0ebb5e04e9f7ed689db53fb12c76e68a1f4..2ec90799340016b7ed905774543a6b94174a74e8 100644 (file)
@@ -1110,6 +1110,7 @@ static int is_firmware_flash_cmd(u8 *cdb)
  */
 #define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
 #define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
+#define HPSA_EVENT_MONITOR_INTERVAL (15 * HZ)
 static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
                struct CommandList *c)
 {
@@ -8661,15 +8662,10 @@ out:
        return rc;
 }
 
-static void hpsa_rescan_ctlr_worker(struct work_struct *work)
+static void hpsa_perform_rescan(struct ctlr_info *h)
 {
+       struct Scsi_Host *sh = NULL;
        unsigned long flags;
-       struct ctlr_info *h = container_of(to_delayed_work(work),
-                                       struct ctlr_info, rescan_ctlr_work);
-
-
-       if (h->remove_in_progress)
-               return;
 
        /*
         * Do the scan after the reset
@@ -8682,23 +8678,63 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work)
        }
        spin_unlock_irqrestore(&h->reset_lock, flags);
 
-       if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
-               scsi_host_get(h->scsi_host);
+       sh = scsi_host_get(h->scsi_host);
+       if (sh != NULL) {
+               hpsa_scan_start(sh);
+               scsi_host_put(sh);
+               h->drv_req_rescan = 0;
+       }
+}
+
+/*
+ * watch for controller events
+ */
+static void hpsa_event_monitor_worker(struct work_struct *work)
+{
+       struct ctlr_info *h = container_of(to_delayed_work(work),
+                                       struct ctlr_info, event_monitor_work);
+       unsigned long flags;
+
+       spin_lock_irqsave(&h->lock, flags);
+       if (h->remove_in_progress) {
+               spin_unlock_irqrestore(&h->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+
+       if (hpsa_ctlr_needs_rescan(h)) {
                hpsa_ack_ctlr_events(h);
-               hpsa_scan_start(h->scsi_host);
-               scsi_host_put(h->scsi_host);
+               hpsa_perform_rescan(h);
+       }
+
+       spin_lock_irqsave(&h->lock, flags);
+       if (!h->remove_in_progress)
+               schedule_delayed_work(&h->event_monitor_work,
+                                       HPSA_EVENT_MONITOR_INTERVAL);
+       spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static void hpsa_rescan_ctlr_worker(struct work_struct *work)
+{
+       unsigned long flags;
+       struct ctlr_info *h = container_of(to_delayed_work(work),
+                                       struct ctlr_info, rescan_ctlr_work);
+
+       spin_lock_irqsave(&h->lock, flags);
+       if (h->remove_in_progress) {
+               spin_unlock_irqrestore(&h->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+
+       if (h->drv_req_rescan || hpsa_offline_devices_ready(h)) {
+               hpsa_perform_rescan(h);
        } else if (h->discovery_polling) {
                hpsa_disable_rld_caching(h);
                if (hpsa_luns_changed(h)) {
-                       struct Scsi_Host *sh = NULL;
-
                        dev_info(&h->pdev->dev,
                                "driver discovery polling rescan.\n");
-                       sh = scsi_host_get(h->scsi_host);
-                       if (sh != NULL) {
-                               hpsa_scan_start(sh);
-                               scsi_host_put(sh);
-                       }
+                       hpsa_perform_rescan(h);
                }
        }
        spin_lock_irqsave(&h->lock, flags);
@@ -8964,6 +9000,9 @@ reinit_after_soft_reset:
        INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker);
        queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
                                h->heartbeat_sample_interval);
+       INIT_DELAYED_WORK(&h->event_monitor_work, hpsa_event_monitor_worker);
+       schedule_delayed_work(&h->event_monitor_work,
+                               HPSA_EVENT_MONITOR_INTERVAL);
        return 0;
 
 clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */
@@ -9132,6 +9171,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
        spin_unlock_irqrestore(&h->lock, flags);
        cancel_delayed_work_sync(&h->monitor_ctlr_work);
        cancel_delayed_work_sync(&h->rescan_ctlr_work);
+       cancel_delayed_work_sync(&h->event_monitor_work);
        destroy_workqueue(h->rescan_ctlr_wq);
        destroy_workqueue(h->resubmit_wq);
 
index 61dd54aa4d5d3f1f88f25cab6d8053b2d1c5d933..c9c4927f5d0e800c7b0772b22955e283bb692e83 100644 (file)
@@ -245,6 +245,7 @@ struct ctlr_info {
        u32 __percpu *lockup_detected;
        struct delayed_work monitor_ctlr_work;
        struct delayed_work rescan_ctlr_work;
+       struct delayed_work event_monitor_work;
        int remove_in_progress;
        /* Address of h->q[x] is passed to intr handler to know which queue */
        u8 q[MAX_REPLY_QUEUES];