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 |   16 +++++++++++-----
 drivers/md/dm-table.c |   10 +++++++---
 2 files changed, 18 insertions(+), 8 deletions(-)

--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -241,8 +241,8 @@ static void __pg_init_all_paths(struct m
 		pg_init_delay = msecs_to_jiffies(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT ?
 						 m->pg_init_delay_msecs : DM_PG_INIT_DELAY_MSECS);
 	list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) {
-		/* Skip failed paths */
-		if (!pgpath->is_active)
+		/* Skip disabled paths or failed paths */
+		if (!pgpath->path.dev || !pgpath->is_active)
 			continue;
 		if (queue_delayed_work(kmpath_handlerd, &pgpath->activate_path,
 				       pg_init_delay))
@@ -1242,8 +1242,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("Could not failover device %s: Handler scsi_dh_%s "
+		      "Error %d.", pgpath->path.pdev,
+		      m->hw_handler_name, errors);
 		/*
 		 * Fail path for now, so we do not ping pong
 		 */
@@ -1256,6 +1257,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;
 	case SCSI_DH_RETRY:
 		/* Wait before retrying. */
 		delay_retry = 1;
@@ -1277,7 +1282,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
@@ -438,14 +438,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 == -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;
@@ -507,7 +511,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;
