[SCSI] hpsa: rescan devices on ioaccel2 error

Allow driver to schedule a rescan whenever a request fails on the ioaccel2 path.
This eliminates the possibility of driver getting stuck in non-ioaccel mode.

IOaccel mode (HP SSD Smart Path) is disabled by driver upon error detection.
Driver relied on idea that request would be retried through normal path, and a
subsequent error would occur on that path, and be processed by controller
firmware.  As part of that process, controller disables ioaccel mode and later
reinstates it, signalling driver to change modes.

In some error cases, the error will not duplicate on the standard path,
so the driver could get stuck in non-ioaccel mode.
To avoid that, we allow driver to request a rescan during the next run of the
rescan thread.

Signed-off-by: Scott Teel <scott.teel@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index a599a7b..dab1d79 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1457,6 +1457,7 @@
 				"%s: Error 0x%02x, Retrying on standard path.\n",
 				"HP SSD Smart Path", c2->error_data.status);
 		dev->offload_enabled = 0;
+		h->drv_req_rescan = 1;	/* schedule controller for a rescan */
 		cmd->result = DID_SOFT_ERROR << 16;
 		cmd_free(h, c);
 		cmd->scsi_done(cmd);
@@ -6138,6 +6139,9 @@
 	int i;
 	char *event_type;
 
+	/* Clear the driver-requested rescan flag */
+	h->drv_req_rescan = 0;
+
 	/* Ask the controller to clear the events we're handling. */
 	if ((h->transMethod & (CFGTBL_Trans_io_accel1
 			| CFGTBL_Trans_io_accel2)) &&
@@ -6185,7 +6189,9 @@
 
 /* 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
+ * we should rescan the controller for devices.
+ * Also check flag for driver-initiated rescan.
+ * If either flag or controller event indicate rescan, add the controller
  * to the list of controllers needing to be rescanned, and gets a
  * reference to the associated scsi_host.
  */
@@ -6195,7 +6201,7 @@
 		return;
 
 	h->events = readl(&(h->cfgtable->event_notify));
-	if (!h->events)
+	if (!h->events && !h->drv_req_rescan)
 		return;
 
 	/*
@@ -6369,6 +6375,8 @@
 	/* Enable Accelerated IO path at driver layer */
 	h->acciopath_status = 1;
 
+	h->drv_req_rescan = 0;
+
 	/* Turn the interrupts on so we can service requests */
 	h->access.set_intr_mask(h, HPSA_INTR_ON);