From: Hannes Reinecke <hare@suse.de>
Subject: DM-MPIO fails to tresspass LUNs on CLARiiON arrays
Reference: bnc#484529
Patch-mainline: Not yet

On Clariion arrays we fail to send the trespass command correctly.
We're trying to send the trespass command to via an disabled path,
causing the device handler to loop trying to send the command on
an invalid path.

Signed-off-by: Hannes Reinecke <hare@suse.de>

---
 drivers/md/dm-mpath.c |   12 +++++++++---
 drivers/md/dm-table.c |   12 ++++++++----
 2 files changed, 17 insertions(+), 7 deletions(-)

--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1228,8 +1228,9 @@ static void pg_init_done(void *data, int
 			errors = 0;
 			break;
 		}
-		DMERR("Could not failover the device: Handler scsi_dh_%s "
-		      "Error %d.", m->hw_handler_name, errors);
+		DMERR("Count not failover device %s: Handler scsi_dh_%s "
+		      "was not loaded.", pgpath->path.pdev,
+		      m->hw_handler_name);
 		/*
 		 * Fail path for now, so we do not ping pong
 		 */
@@ -1242,6 +1243,10 @@ static void pg_init_done(void *data, int
 		 */
 		bypass_pg(m, pg, 1);
 		break;
+	case SCSI_DH_DEV_OFFLINED:
+		DMWARN("Device %s offlined.", pgpath->path.pdev);
+		errors = 0;
+		break;
 	/* TODO: For SCSI_DH_RETRY we should wait a couple seconds */
 	case SCSI_DH_RETRY:
 	case SCSI_DH_IMM_RETRY:
@@ -1262,7 +1267,8 @@ static void pg_init_done(void *data, int
 	spin_lock_irqsave(&m->lock, flags);
 	if (errors) {
 		if (pgpath == m->current_pgpath) {
-			DMERR("Could not failover device. Error %d.", errors);
+			DMERR("Could not failover device %s, error %d.",
+			      pgpath->path.pdev, errors);
 			m->current_pgpath = NULL;
 			m->current_pg = NULL;
 		}
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -411,14 +411,18 @@ static int upgrade_mode(struct dm_dev_in
 
 	dd_new = dd_old = *dd;
 
-	dd_new.dm_dev.mode |= new_mode;
+	dd_new.dm_dev.mode = new_mode;
 	dd_new.dm_dev.bdev = NULL;
 
 	r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
-	if (r)
+	if (r == -EROFS) {
+		dd_new.dm_dev.mode &= ~FMODE_WRITE;
+		r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
+	}
+	if (!r)
 		return r;
 
-	dd->dm_dev.mode |= new_mode;
+	dd->dm_dev.mode = new_mode;
 	close_dev(&dd_old, md);
 
 	return 0;
@@ -480,7 +484,7 @@ static int __table_get_device(struct dm_
 		atomic_set(&dd->count, 0);
 		list_add(&dd->list, &t->devices);
 
-	} else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
+	} else if (dd->dm_dev.mode != mode) {
 		r = upgrade_mode(dd, mode, t->md);
 		if (r)
 			return r;
