[SCSI] scsi_dh: Change the scsidh_activate interface to be asynchronous
authorChandra Seetharaman <sekharan@us.ibm.com>
Wed, 21 Oct 2009 16:22:46 +0000 (09:22 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Fri, 4 Dec 2009 18:00:46 +0000 (12:00 -0600)
Make scsi_dh_activate() function asynchronous, by taking in two additional
parameters, one is the callback function and the other is the data to call
the callback function with.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

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

index 32d0b87..dce971d 100644 (file)
@@ -1116,8 +1116,9 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
        return limit_reached;
 }
 
-static void pg_init_done(struct dm_path *path, int errors)
+static void pg_init_done(void *data, int errors)
 {
+       struct dm_path *path = data;
        struct pgpath *pgpath = path_to_pgpath(path);
        struct priority_group *pg = pgpath->pg;
        struct multipath *m = pg->m;
@@ -1183,12 +1184,11 @@ static void pg_init_done(struct dm_path *path, int errors)
 
 static void activate_path(struct work_struct *work)
 {
-       int ret;
        struct pgpath *pgpath =
                container_of(work, struct pgpath, activate_path);
 
-       ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev));
-       pg_init_done(&pgpath->path, ret);
+       scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
+                               pg_init_done, &pgpath->path);
 }
 
 /*
index 3ee1cbc..6f7f798 100644 (file)
@@ -226,7 +226,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
                         * Activate a device handler
                         */
                        if (scsi_dh->activate)
-                               err = scsi_dh->activate(sdev);
+                               err = scsi_dh->activate(sdev, NULL, NULL);
                        else
                                err = 0;
                }
@@ -423,10 +423,17 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 /*
  * scsi_dh_activate - activate the path associated with the scsi_device
  *      corresponding to the given request queue.
- * @q - Request queue that is associated with the scsi_device to be
- *      activated.
+ *     Returns immediately without waiting for activation to be completed.
+ * @q    - Request queue that is associated with the scsi_device to be
+ *         activated.
+ * @fn   - Function to be called upon completion of the activation.
+ *         Function fn is called with data (below) and the error code.
+ *         Function fn may be called from the same calling context. So,
+ *         do not hold the lock in the caller which may be needed in fn.
+ * @data - data passed to the function fn upon completion.
+ *
  */
-int scsi_dh_activate(struct request_queue *q)
+int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
 {
        int err = 0;
        unsigned long flags;
@@ -445,7 +452,7 @@ int scsi_dh_activate(struct request_queue *q)
                return err;
 
        if (scsi_dh->activate)
-               err = scsi_dh->activate(sdev);
+               err = scsi_dh->activate(sdev, fn, data);
        put_device(&sdev->sdev_gendev);
        return err;
 }
index b5cdefa..e8a8928 100644 (file)
@@ -652,7 +652,8 @@ out:
  * based on a certain policy. But until we actually encounter them it
  * should be okay.
  */
-static int alua_activate(struct scsi_device *sdev)
+static int alua_activate(struct scsi_device *sdev,
+                       activate_complete fn, void *data)
 {
        struct alua_dh_data *h = get_alua_data(sdev);
        int err = SCSI_DH_OK;
@@ -667,7 +668,9 @@ static int alua_activate(struct scsi_device *sdev)
                err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
 
 out:
-       return err;
+       if (fn)
+               fn(data, err);
+       return 0;
 }
 
 /*
index 0cffe84..6196675 100644 (file)
@@ -528,7 +528,8 @@ retry:
        return err;
 }
 
-static int clariion_activate(struct scsi_device *sdev)
+static int clariion_activate(struct scsi_device *sdev,
+                               activate_complete fn, void *data)
 {
        struct clariion_dh_data *csdev = get_clariion_data(sdev);
        int result;
@@ -559,7 +560,9 @@ done:
                    csdev->port, lun_state[csdev->lun_state],
                    csdev->default_sp + 'A');
 
-       return result;
+       if (fn)
+               fn(data, result);
+       return 0;
 }
 /*
  * params - parameters in the following format
index f7da753..0aacafc 100644 (file)
@@ -268,7 +268,8 @@ static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
  * activate the passive path (and deactivate the
  * previously active one).
  */
-static int hp_sw_activate(struct scsi_device *sdev)
+static int hp_sw_activate(struct scsi_device *sdev,
+                               activate_complete fn, void *data)
 {
        int ret = SCSI_DH_OK;
        struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
@@ -283,7 +284,9 @@ static int hp_sw_activate(struct scsi_device *sdev)
                                    HP_SW_NAME);
        }
 
-       return ret;
+       if (fn)
+               fn(data, ret);
+       return 0;
 }
 
 static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
index 268189d..be362ad 100644 (file)
@@ -568,7 +568,8 @@ done:
        return err;
 }
 
-static int rdac_activate(struct scsi_device *sdev)
+static int rdac_activate(struct scsi_device *sdev,
+                       activate_complete fn, void *data)
 {
        struct rdac_dh_data *h = get_rdac_data(sdev);
        int err = SCSI_DH_OK;
@@ -580,7 +581,9 @@ static int rdac_activate(struct scsi_device *sdev)
        if (h->lun_state == RDAC_LUN_UNOWNED)
                err = send_mode_select(sdev, h);
 done:
-       return err;
+       if (fn)
+               fn(data, err);
+       return 0;
 }
 
 static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
index 92c4c3b..68d185c 100644 (file)
@@ -177,6 +177,7 @@ struct scsi_dh_devlist {
        char *model;
 };
 
+typedef void (*activate_complete)(void *, int);
 struct scsi_device_handler {
        /* Used by the infrastructure */
        struct list_head list; /* list of scsi_device_handlers */
@@ -188,7 +189,7 @@ struct scsi_device_handler {
        int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
        int (*attach)(struct scsi_device *);
        void (*detach)(struct scsi_device *);
-       int (*activate)(struct scsi_device *);
+       int (*activate)(struct scsi_device *, activate_complete, void *);
        int (*prep_fn)(struct scsi_device *, struct request *);
        int (*set_params)(struct scsi_device *, const char *);
 };
index ff24074..e3f2db2 100644 (file)
@@ -56,14 +56,16 @@ enum {
        SCSI_DH_DRIVER_MAX,
 };
 #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
-extern int scsi_dh_activate(struct request_queue *);
+extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
 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)
+static inline int scsi_dh_activate(struct request_queue *req,
+                                       activate_complete fn, void *data)
 {
+       fn(data, 0);
        return 0;
 }
 static inline int scsi_dh_handler_exist(const char *name)