static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
 #define BOARD_NOT_READY 0
 #define BOARD_READY 1
+static void hpsa_drain_commands(struct ctlr_info *h);
+static void hpsa_flush_cache(struct ctlr_info *h);
 
 static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
 {
        writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
 }
 
+static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
+{
+       int i;
+       u32 doorbell_value;
+       unsigned long flags;
+       /* wait until the clear_event_notify bit 6 is cleared by controller. */
+       for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+               spin_lock_irqsave(&h->lock, flags);
+               doorbell_value = readl(h->vaddr + SA5_DOORBELL);
+               spin_unlock_irqrestore(&h->lock, flags);
+               if (!(doorbell_value & DOORBELL_CLEAR_EVENTS))
+                       break;
+               /* delay and try again */
+               msleep(20);
+       }
+}
+
 static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
 {
        int i;
        h->last_heartbeat_timestamp = now;
 }
 
+static int hpsa_kickoff_rescan(struct ctlr_info *h)
+{
+       int i;
+       char *event_type;
+
+       /* Ask the controller to clear the events we're handling. */
+       if (h->transMethod & (CFGTBL_Trans_io_accel1) &&
+               (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
+                h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
+
+               if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
+                       event_type = "state change";
+               if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
+                       event_type = "configuration change";
+               /* Stop sending new RAID offload reqs via the IO accelerator */
+               scsi_block_requests(h->scsi_host);
+               for (i = 0; i < h->ndevices; i++)
+                       h->dev[i]->offload_enabled = 0;
+               hpsa_drain_commands(h);
+               /* Set 'accelerator path config change' bit */
+               dev_warn(&h->pdev->dev,
+                       "Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
+                       h->events, event_type);
+               writel(h->events, &(h->cfgtable->clear_event_notify));
+               /* Set the "clear event notify field update" bit 6 */
+               writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+               /* Wait until ctlr clears 'clear event notify field', bit 6 */
+               hpsa_wait_for_clear_event_notify_ack(h);
+               scsi_unblock_requests(h->scsi_host);
+       } else {
+               /* Acknowledge controller notification events. */
+               writel(h->events, &(h->cfgtable->clear_event_notify));
+               writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+               hpsa_wait_for_clear_event_notify_ack(h);
+#if 0
+               writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+               hpsa_wait_for_mode_change_ack(h);
+#endif
+       }
+
+       /* Something in the device list may have changed to trigger
+        * the event, so do a rescan.
+        */
+       hpsa_scan_start(h->scsi_host);
+       /* release reference taken on scsi host in check_controller_events */
+       scsi_host_put(h->scsi_host);
+       return 0;
+}
+
+/* Check a register on the controller to see if there are configuration
+ * changes (added/changed/removed logical drives, etc.) which mean that
+ * we should rescan the controller for devices.  If so, add the controller
+ * to the list of controllers needing to be rescanned, and gets a
+ * reference to the associated scsi_host.
+ */
+static void hpsa_ctlr_needs_rescan(struct ctlr_info *h)
+{
+       if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
+               return;
+
+       h->events = readl(&(h->cfgtable->event_notify));
+       if (!h->events)
+               return;
+
+       /*
+        * Take a reference on scsi host for the duration of the scan
+        * Release in hpsa_kickoff_rescan().  No lock needed for scan_list
+        * as only a single thread accesses this list.
+        */
+       scsi_host_get(h->scsi_host);
+       hpsa_kickoff_rescan(h);
+}
+
 static void hpsa_monitor_ctlr_worker(struct work_struct *work)
 {
        unsigned long flags;
        detect_controller_lockup(h);
        if (h->lockup_detected)
                return;
+       hpsa_ctlr_needs_rescan(h);
        spin_lock_irqsave(&h->lock, flags);
        if (h->remove_in_progress) {
                spin_unlock_irqrestore(&h->lock, flags);
        kfree(h->blockFetchTable);
 }
 
+static void hpsa_drain_commands(struct ctlr_info *h)
+{
+       int cmds_out;
+       unsigned long flags;
+
+       do { /* wait for all outstanding commands to drain out */
+               spin_lock_irqsave(&h->lock, flags);
+               cmds_out = h->commands_outstanding;
+               spin_unlock_irqrestore(&h->lock, flags);
+               if (cmds_out <= 0)
+                       break;
+               msleep(100);
+       } while (1);
+}
+
 /*
  *  This is it.  Register the PCI driver information for the cards we control
  *  the OS will call our registered routines when it finds one of our cards.