]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/md/dm-mpath.c
MIPS: OCTEON: Add support for cn68XX interrupt controller.
[mirror_ubuntu-zesty-kernel.git] / drivers / md / dm-mpath.c
index 638dae048b4fada0633f2592538ee16535072b87..d8abb90a6c2fbecae99ae2de09ebc2f3d726731e 100644 (file)
@@ -85,6 +85,7 @@ struct multipath {
        unsigned queue_io:1;            /* Must we queue all I/O? */
        unsigned queue_if_no_path:1;    /* Queue I/O if last path fails? */
        unsigned saved_queue_if_no_path:1; /* Saved state during suspension */
+       unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */
 
        unsigned pg_init_retries;       /* Number of times to retry pg_init */
        unsigned pg_init_count;         /* Number of times pg_init called */
@@ -568,6 +569,8 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
        int r;
        struct pgpath *p;
        struct multipath *m = ti->private;
+       struct request_queue *q = NULL;
+       const char *attached_handler_name;
 
        /* we need at least a path arg */
        if (as->argc < 1) {
@@ -586,13 +589,37 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
                goto bad;
        }
 
-       if (m->hw_handler_name) {
-               struct request_queue *q = bdev_get_queue(p->path.dev->bdev);
+       if (m->retain_attached_hw_handler || m->hw_handler_name)
+               q = bdev_get_queue(p->path.dev->bdev);
+
+       if (m->retain_attached_hw_handler) {
+               attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
+               if (attached_handler_name) {
+                       /*
+                        * Reset hw_handler_name to match the attached handler
+                        * and clear any hw_handler_params associated with the
+                        * ignored handler.
+                        *
+                        * NB. This modifies the table line to show the actual
+                        * handler instead of the original table passed in.
+                        */
+                       kfree(m->hw_handler_name);
+                       m->hw_handler_name = attached_handler_name;
+
+                       kfree(m->hw_handler_params);
+                       m->hw_handler_params = NULL;
+               }
+       }
 
+       if (m->hw_handler_name) {
+               /*
+                * Increments scsi_dh reference, even when using an
+                * already-attached handler.
+                */
                r = scsi_dh_attach(q, m->hw_handler_name);
                if (r == -EBUSY) {
                        /*
-                        * Already attached to different hw_handler,
+                        * Already attached to different hw_handler:
                         * try to reattach with correct one.
                         */
                        scsi_dh_detach(q);
@@ -760,7 +787,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
        const char *arg_name;
 
        static struct dm_arg _args[] = {
-               {0, 5, "invalid number of feature args"},
+               {0, 6, "invalid number of feature args"},
                {1, 50, "pg_init_retries must be between 1 and 50"},
                {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"},
        };
@@ -781,6 +808,11 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
                        continue;
                }
 
+               if (!strcasecmp(arg_name, "retain_attached_hw_handler")) {
+                       m->retain_attached_hw_handler = 1;
+                       continue;
+               }
+
                if (!strcasecmp(arg_name, "pg_init_retries") &&
                    (argc >= 1)) {
                        r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error);
@@ -1346,7 +1378,7 @@ static void multipath_resume(struct dm_target *ti)
  *      num_paths num_selector_args [path_dev [selector_args]* ]+ ]+
  */
 static int multipath_status(struct dm_target *ti, status_type_t type,
-                           char *result, unsigned int maxlen)
+                           unsigned status_flags, char *result, unsigned maxlen)
 {
        int sz = 0;
        unsigned long flags;
@@ -1364,13 +1396,16 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
        else {
                DMEMIT("%u ", m->queue_if_no_path +
                              (m->pg_init_retries > 0) * 2 +
-                             (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2);
+                             (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 +
+                             m->retain_attached_hw_handler);
                if (m->queue_if_no_path)
                        DMEMIT("queue_if_no_path ");
                if (m->pg_init_retries)
                        DMEMIT("pg_init_retries %u ", m->pg_init_retries);
                if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT)
                        DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs);
+               if (m->retain_attached_hw_handler)
+                       DMEMIT("retain_attached_hw_handler ");
        }
 
        if (!m->hw_handler_name || type == STATUSTYPE_INFO)
@@ -1656,7 +1691,7 @@ out:
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 4, 0},
+       .version = {1, 5, 0},
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,