[SCSI] scsi_dh: Make alua hardware handler's activate() async
authorChandra Seetharaman <sekharan@us.ibm.com>
Wed, 21 Oct 2009 16:23:04 +0000 (09:23 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Fri, 4 Dec 2009 18:00:48 +0000 (12:00 -0600)
Make the activate function asynchronous by using blk_execute_rq_nowait()

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/device_handler/scsi_dh_alua.c

index e8a8928e58bc63e06c021db9ea47c2d228be1077..4f0d0138f48b8af3533b28390ef818567fb24d54 100644 (file)
@@ -60,11 +60,17 @@ struct alua_dh_data {
        int                     bufflen;
        unsigned char           sense[SCSI_SENSE_BUFFERSIZE];
        int                     senselen;
+       struct scsi_device      *sdev;
+       activate_complete       callback_fn;
+       void                    *callback_data;
 };
 
 #define ALUA_POLICY_SWITCH_CURRENT     0
 #define ALUA_POLICY_SWITCH_ALL         1
 
+static char print_alua_state(int);
+static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
+
 static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
 {
        struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
@@ -230,19 +236,72 @@ done:
        return err;
 }
 
+/*
+ * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * @sdev: the device to be evaluated
+ * @state: the new target group state
+ *
+ * Send a SET TARGET GROUP STATES command to the device.
+ * We only have to test here if we should resubmit the command;
+ * any other error is assumed as a failure.
+ */
+static void stpg_endio(struct request *req, int error)
+{
+       struct alua_dh_data *h = req->end_io_data;
+       struct scsi_sense_hdr sense_hdr;
+       unsigned err = SCSI_DH_IO;
+
+       if (error || host_byte(req->errors) != DID_OK ||
+                       msg_byte(req->errors) != COMMAND_COMPLETE)
+               goto done;
+
+       if (err == SCSI_DH_IO && h->senselen > 0) {
+               err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+                                          &sense_hdr);
+               if (!err) {
+                       err = SCSI_DH_IO;
+                       goto done;
+               }
+               err = alua_check_sense(h->sdev, &sense_hdr);
+               if (err == ADD_TO_MLQUEUE) {
+                       err = SCSI_DH_RETRY;
+                       goto done;
+               }
+               sdev_printk(KERN_INFO, h->sdev,
+                           "%s: stpg sense code: %02x/%02x/%02x\n",
+                           ALUA_DH_NAME, sense_hdr.sense_key,
+                           sense_hdr.asc, sense_hdr.ascq);
+               err = SCSI_DH_IO;
+       }
+       if (err == SCSI_DH_OK) {
+               h->state = TPGS_STATE_OPTIMIZED;
+               sdev_printk(KERN_INFO, h->sdev,
+                           "%s: port group %02x switched to state %c\n",
+                           ALUA_DH_NAME, h->group_id,
+                           print_alua_state(h->state));
+       }
+done:
+       blk_put_request(req);
+       if (h->callback_fn) {
+               h->callback_fn(h->callback_data, err);
+               h->callback_fn = h->callback_data = NULL;
+       }
+       return;
+}
+
 /*
  * submit_stpg - Issue a SET TARGET GROUP STATES command
- * @sdev: sdev the command should be sent to
  *
  * Currently we're only setting the current target port group state
  * to 'active/optimized' and let the array firmware figure out
  * the states of the remaining groups.
  */
-static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_stpg(struct alua_dh_data *h)
 {
        struct request *rq;
        int err = SCSI_DH_RES_TEMP_UNAVAIL;
        int stpg_len = 8;
+       struct scsi_device *sdev = h->sdev;
 
        /* Prepare the data buffer */
        memset(h->buff, 0, stpg_len);
@@ -252,7 +311,7 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
 
        rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
        if (!rq)
-               goto done;
+               return SCSI_DH_RES_TEMP_UNAVAIL;
 
        /* Prepare the command. */
        rq->cmd[0] = MAINTENANCE_OUT;
@@ -266,17 +325,9 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
        rq->sense = h->sense;
        memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
        rq->sense_len = h->senselen = 0;
+       rq->end_io_data = h;
 
-       err = blk_execute_rq(rq->q, NULL, rq, 1);
-       if (err == -EIO) {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: stpg failed with %x\n",
-                           ALUA_DH_NAME, rq->errors);
-               h->senselen = rq->sense_len;
-               err = SCSI_DH_IO;
-       }
-       blk_put_request(rq);
-done:
+       blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
        return err;
 }
 
@@ -476,50 +527,6 @@ static int alua_check_sense(struct scsi_device *sdev,
        return SCSI_RETURN_NOT_HANDLED;
 }
 
-/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
- */
-static int alua_stpg(struct scsi_device *sdev, int state,
-                    struct alua_dh_data *h)
-{
-       struct scsi_sense_hdr sense_hdr;
-       unsigned err;
-       int retry = ALUA_FAILOVER_RETRIES;
-
- retry:
-       err = submit_stpg(sdev, h);
-       if (err == SCSI_DH_IO && h->senselen > 0) {
-               err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-                                          &sense_hdr);
-               if (!err)
-                       return SCSI_DH_IO;
-               err = alua_check_sense(sdev, &sense_hdr);
-               if (retry > 0 && err == ADD_TO_MLQUEUE) {
-                       retry--;
-                       goto retry;
-               }
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: stpg sense code: %02x/%02x/%02x\n",
-                           ALUA_DH_NAME, sense_hdr.sense_key,
-                           sense_hdr.asc, sense_hdr.ascq);
-               err = SCSI_DH_IO;
-       }
-       if (err == SCSI_DH_OK) {
-               h->state = state;
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: port group %02x switched to state %c\n",
-                           ALUA_DH_NAME, h->group_id,
-                           print_alua_state(h->state) );
-       }
-       return err;
-}
-
 /*
  * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
  * @sdev: the device to be evaluated.
@@ -664,8 +671,14 @@ static int alua_activate(struct scsi_device *sdev,
                        goto out;
        }
 
-       if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
-               err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
+       if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) {
+               h->callback_fn = fn;
+               h->callback_data = data;
+               err = submit_stpg(h);
+               if (err == SCSI_DH_OK)
+                       return 0;
+               h->callback_fn = h->callback_data = NULL;
+       }
 
 out:
        if (fn)
@@ -748,6 +761,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
        h->rel_port = -1;
        h->buff = h->inq;
        h->bufflen = ALUA_INQUIRY_SIZE;
+       h->sdev = sdev;
 
        err = alua_initialize(sdev, h);
        if (err != SCSI_DH_OK)