[SCSI] hpsa: dial down lockup detection during firmware flash
[pandora-kernel.git] / drivers / scsi / hpsa.c
index 0f0aac9..796482b 100644 (file)
@@ -569,12 +569,42 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
        }
 }
 
+static int is_firmware_flash_cmd(u8 *cdb)
+{
+       return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
+}
+
+/*
+ * During firmware flash, the heartbeat register may not update as frequently
+ * as it should.  So we dial down lockup detection during firmware flash. and
+ * dial it back up when firmware flash completes.
+ */
+#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
+#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
+static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
+               struct CommandList *c)
+{
+       if (!is_firmware_flash_cmd(c->Request.CDB))
+               return;
+       atomic_inc(&h->firmware_flash_in_progress);
+       h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
+}
+
+static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
+               struct CommandList *c)
+{
+       if (is_firmware_flash_cmd(c->Request.CDB) &&
+               atomic_dec_and_test(&h->firmware_flash_in_progress))
+               h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
+}
+
 static void enqueue_cmd_and_start_io(struct ctlr_info *h,
        struct CommandList *c)
 {
        unsigned long flags;
 
        set_performant_mode(h, c);
+       dial_down_lockup_detection_during_fw_flash(h, c);
        spin_lock_irqsave(&h->lock, flags);
        addQ(&h->reqQ, c);
        h->Qdepth++;
@@ -3385,6 +3415,7 @@ static inline void finish_cmd(struct CommandList *c)
        spin_lock_irqsave(&c->h->lock, flags);
        removeQ(c);
        spin_unlock_irqrestore(&c->h->lock, flags);
+       dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
        if (likely(c->cmd_type == CMD_SCSI))
                complete_scsi_command(c);
        else if (c->cmd_type == CMD_IOCTL_PEND)
@@ -4562,9 +4593,6 @@ static void controller_lockup_detected(struct ctlr_info *h)
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
-#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ)
-#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2)
-
 static void detect_controller_lockup(struct ctlr_info *h)
 {
        u64 now;
@@ -4575,7 +4603,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
        now = get_jiffies_64();
        /* If we've received an interrupt recently, we're ok. */
        if (time_after64(h->last_intr_timestamp +
-                               (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+                               (h->heartbeat_sample_interval), now))
                return;
 
        /*
@@ -4584,7 +4612,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
         * otherwise don't care about signals in this thread.
         */
        if (time_after64(h->last_heartbeat_timestamp +
-                               (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+                               (h->heartbeat_sample_interval), now))
                return;
 
        /* If heartbeat has not changed since we last looked, we're not ok. */
@@ -4626,6 +4654,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h)
 {
        unsigned long flags;
 
+       h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
        spin_lock_irqsave(&lockup_detector_lock, flags);
        list_add_tail(&h->lockup_list, &hpsa_ctlr_list);
        spin_unlock_irqrestore(&lockup_detector_lock, flags);