- patches.fixes/scsi_dh-Provide-set_params-interface-in-emc-device-handler.patch:
authorNikanth Karthikesan <knikanth@suse.de>
Tue, 8 Sep 2009 13:03:58 +0000 (15:03 +0200)
committerNikanth Karthikesan <knikanth@suse.de>
Tue, 8 Sep 2009 13:03:58 +0000 (15:03 +0200)
  scsi_dh: Provide set_params interface in emc device handler
  (bnc#521607).
- patches.fixes/scsi_dh-Use-scsi_dh_set_params-in-multipath.patch:
  scsi_dh: Use scsi_dh_set_params() in multipath. (bnc#521607).
- patches.fixes/scsi_dh-add-the-interface-scsi_dh_set_params.patch:
  scsi_dh: add the interface scsi_dh_set_params() (bnc#521607).

suse-commit: 2f05d5c59b9106e8483245732af4615bcfd18f75

drivers/md/dm-mpath.c
drivers/scsi/device_handler/scsi_dh.c
drivers/scsi/device_handler/scsi_dh_emc.c
include/scsi/scsi_device.h
include/scsi/scsi_dh.h

index 1768053..d589993 100644 (file)
@@ -64,6 +64,7 @@ struct multipath {
        spinlock_t lock;
 
        const char *hw_handler_name;
+       char *hw_handler_params;
        unsigned nr_priority_groups;
        struct list_head priority_groups;
        unsigned pg_init_required;      /* pg_init needs calling? */
@@ -217,6 +218,7 @@ static void free_multipath(struct multipath *m)
        }
 
        kfree(m->hw_handler_name);
+       kfree(m->hw_handler_params);
        mempool_destroy(m->mpio_pool);
        kfree(m);
 }
@@ -613,6 +615,17 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
                        dm_put_device(ti, p->path.dev);
                        goto bad;
                }
+
+               if (m->hw_handler_params) {
+                       r = scsi_dh_set_params(q, m->hw_handler_params);
+                       if (r < 0) {
+                               ti->error = "unable to set hardware "
+                                                       "handler parameters";
+                               scsi_dh_detach(q);
+                               dm_put_device(ti, p->path.dev);
+                               goto bad;
+                       }
+               }
        }
 
        r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
@@ -703,6 +716,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
 static int parse_hw_handler(struct arg_set *as, struct multipath *m)
 {
        unsigned hw_argc;
+       int ret;
        struct dm_target *ti = m->ti;
 
        static struct param _params[] = {
@@ -724,17 +738,33 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
        request_module("scsi_dh_%s", m->hw_handler_name);
        if (scsi_dh_handler_exist(m->hw_handler_name) == 0) {
                ti->error = "unknown hardware handler type";
-               kfree(m->hw_handler_name);
-               m->hw_handler_name = NULL;
-               return -EINVAL;
+               ret = -EINVAL;
+               goto fail;
        }
 
-       if (hw_argc > 1)
-               DMWARN("Ignoring user-specified arguments for "
-                      "hardware handler \"%s\"", m->hw_handler_name);
+       if (hw_argc > 1) {
+               char *p;
+               int i, j, len = 4;
+
+               for (i = 0; i <= hw_argc - 2; i++)
+                       len += strlen(as->argv[i]) + 1;
+               p = m->hw_handler_params = kzalloc(len, GFP_KERNEL);
+               if (!p) {
+                       ti->error = "memory allocation failed";
+                       ret = -ENOMEM;
+                       goto fail;
+               }
+               j = sprintf(p, "%d", hw_argc - 1);
+               for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1)
+                       j = sprintf(p, "%s", as->argv[i]);
+       }
        consume(as, hw_argc - 1);
 
        return 0;
+fail:
+       kfree(m->hw_handler_name);
+       m->hw_handler_name = NULL;
+       return ret;
 }
 
 static int parse_features(struct arg_set *as, struct multipath *m)
index 328ead8..4ffc13c 100644 (file)
@@ -445,6 +445,39 @@ int scsi_dh_activate(struct request_queue *q)
 EXPORT_SYMBOL_GPL(scsi_dh_activate);
 
 /*
+ * scsi_dh_set_params - set the parameters for the device as per the
+ *      string specified in params.
+ * @q - Request queue that is associated with the scsi_device for
+ *      which the parameters to be set.
+ * @params - parameters in the following format
+ *      "no_of_params\0param1\0param2\0param3\0...\0"
+ *      for example, string for 2 parameters with value 10 and 21
+ *      is specified as "2\010\021\0".
+ */
+int scsi_dh_set_params(struct request_queue *q, const char *params)
+{
+       int err = -SCSI_DH_NOSYS;
+       unsigned long flags;
+       struct scsi_device *sdev;
+       struct scsi_device_handler *scsi_dh = NULL;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       sdev = q->queuedata;
+       if (sdev && sdev->scsi_dh_data)
+               scsi_dh = sdev->scsi_dh_data->scsi_dh;
+       if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
+               err = 0;
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       if (err)
+               return err;
+       err = scsi_dh->set_params(sdev, params);
+       put_device(&sdev->sdev_gendev);
+       return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_set_params);
+
+/*
  * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
  *     the given name. FALSE(0) otherwise.
  * @name - name of the device handler.
index ff2e653..d03e2f3 100644 (file)
@@ -561,6 +561,61 @@ done:
 
        return result;
 }
+/*
+ * params - parameters in the following format
+ *      "no_of_params\0param1\0param2\0param3\0...\0"
+ *      for example, string for 2 parameters with value 10 and 21
+ *      is specified as "2\010\021\0".
+ */
+static int clariion_set_params(struct scsi_device *sdev, const char *params)
+{
+       struct clariion_dh_data *csdev = get_clariion_data(sdev);
+       unsigned int hr = 0, st = 0, argc;
+       const char *p = params;
+       int result = SCSI_DH_OK;
+
+       if ((sscanf(params, "%u", &argc) != 1) || (argc != 2))
+               return -EINVAL;
+
+       while (*p++)
+               ;
+       if ((sscanf(p, "%u", &st) != 1) || (st > 1))
+               return -EINVAL;
+
+       while (*p++)
+               ;
+       if ((sscanf(p, "%u", &hr) != 1) || (hr > 1))
+               return -EINVAL;
+
+       if (st)
+               csdev->flags |= CLARIION_SHORT_TRESPASS;
+       else
+               csdev->flags &= ~CLARIION_SHORT_TRESPASS;
+
+       if (hr)
+               csdev->flags |= CLARIION_HONOR_RESERVATIONS;
+       else
+               csdev->flags &= ~CLARIION_HONOR_RESERVATIONS;
+
+       /*
+        * If this path is owned, we have to send a trespass command
+        * with the new parameters. If not, simply return. Next trespass
+        * command would use the parameters.
+        */
+       if (csdev->lun_state != CLARIION_LUN_OWNED)
+               goto done;
+
+       csdev->lun_state = CLARIION_LUN_UNINITIALIZED;
+       result = send_trespass_cmd(sdev, csdev);
+       if (result != SCSI_DH_OK)
+               goto done;
+
+       /* Update status */
+       result = clariion_send_inquiry(sdev, csdev);
+
+done:
+       return result;
+}
 
 static const struct scsi_dh_devlist clariion_dev_list[] = {
        {"DGC", "RAID", 0},
@@ -581,11 +636,9 @@ static struct scsi_device_handler clariion_dh = {
        .check_sense    = clariion_check_sense,
        .activate       = clariion_activate,
        .prep_fn        = clariion_prep_fn,
+       .set_params     = clariion_set_params,
 };
 
-/*
- * TODO: need some interface so we can set trespass values
- */
 static int clariion_bus_attach(struct scsi_device *sdev)
 {
        struct scsi_dh_data *scsi_dh_data;
index d7f1487..607f728 100644 (file)
@@ -189,6 +189,7 @@ struct scsi_device_handler {
        void (*detach)(struct scsi_device *);
        int (*activate)(struct scsi_device *);
        int (*prep_fn)(struct scsi_device *, struct request *);
+       int (*set_params)(struct scsi_device *, const char *);
 };
 
 struct scsi_dh_data {
index 33efce2..ff24074 100644 (file)
@@ -60,6 +60,7 @@ extern int scsi_dh_activate(struct request_queue *);
 extern int scsi_dh_handler_exist(const char *);
 extern int scsi_dh_attach(struct request_queue *, const char *);
 extern void scsi_dh_detach(struct request_queue *);
+extern int scsi_dh_set_params(struct request_queue *, const char *);
 #else
 static inline int scsi_dh_activate(struct request_queue *req)
 {
@@ -77,4 +78,8 @@ static inline void scsi_dh_detach(struct request_queue *q)
 {
        return;
 }
+static inline int scsi_dh_set_params(struct request_queue *req, const char *params)
+{
+       return -SCSI_DH_NOSYS;
+}
 #endif