Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-microblaze.git] / drivers / scsi / scsi_lib.c
index e5fcfa8..1cbc497 100644 (file)
@@ -252,9 +252,9 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
        struct scsi_request *rq;
        int ret = DRIVER_ERROR << 24;
 
-       req = blk_get_request(sdev->request_queue,
+       req = blk_get_request_flags(sdev->request_queue,
                        data_direction == DMA_TO_DEVICE ?
-                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM);
+                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, BLK_MQ_REQ_PREEMPT);
        if (IS_ERR(req))
                return ret;
        rq = scsi_req(req);
@@ -268,7 +268,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
        rq->retries = retries;
        req->timeout = timeout;
        req->cmd_flags |= flags;
-       req->rq_flags |= rq_flags | RQF_QUIET | RQF_PREEMPT;
+       req->rq_flags |= rq_flags | RQF_QUIET;
 
        /*
         * head injection *required* here otherwise quiesce won't work
@@ -1301,7 +1301,7 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
                        /*
                         * If the devices is blocked we defer normal commands.
                         */
-                       if (!(req->rq_flags & RQF_PREEMPT))
+                       if (req && !(req->rq_flags & RQF_PREEMPT))
                                ret = BLKPREP_DEFER;
                        break;
                default:
@@ -1310,7 +1310,7 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
                         * special commands.  In particular any user initiated
                         * command is not allowed.
                         */
-                       if (!(req->rq_flags & RQF_PREEMPT))
+                       if (req && !(req->rq_flags & RQF_PREEMPT))
                                ret = BLKPREP_KILL;
                        break;
                }
@@ -1379,8 +1379,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
 
        ret = scsi_setup_cmnd(sdev, req);
 out:
-       if (ret != BLKPREP_OK)
-               cmd->flags &= ~SCMD_INITIALIZED;
        return scsi_prep_return(q, req, ret);
 }
 
@@ -1903,7 +1901,6 @@ static int scsi_mq_prep_fn(struct request *req)
        struct scsi_device *sdev = req->q->queuedata;
        struct Scsi_Host *shost = sdev->host;
        struct scatterlist *sg;
-       int ret;
 
        scsi_init_command(sdev, cmd);
 
@@ -1937,10 +1934,7 @@ static int scsi_mq_prep_fn(struct request *req)
 
        blk_mq_start_request(req);
 
-       ret = scsi_setup_cmnd(sdev, req);
-       if (ret != BLK_STS_OK)
-               cmd->flags &= ~SCMD_INITIALIZED;
-       return ret;
+       return scsi_setup_cmnd(sdev, req);
 }
 
 static void scsi_mq_done(struct scsi_cmnd *cmd)
@@ -1949,6 +1943,33 @@ static void scsi_mq_done(struct scsi_cmnd *cmd)
        blk_mq_complete_request(cmd->request);
 }
 
+static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx)
+{
+       struct request_queue *q = hctx->queue;
+       struct scsi_device *sdev = q->queuedata;
+
+       atomic_dec(&sdev->device_busy);
+       put_device(&sdev->sdev_gendev);
+}
+
+static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx)
+{
+       struct request_queue *q = hctx->queue;
+       struct scsi_device *sdev = q->queuedata;
+
+       if (!get_device(&sdev->sdev_gendev))
+               goto out;
+       if (!scsi_dev_queue_ready(q, sdev))
+               goto out_put_device;
+
+       return true;
+
+out_put_device:
+       put_device(&sdev->sdev_gendev);
+out:
+       return false;
+}
+
 static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
                         const struct blk_mq_queue_data *bd)
 {
@@ -1962,16 +1983,11 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
 
        ret = prep_to_mq(scsi_prep_state_check(sdev, req));
        if (ret != BLK_STS_OK)
-               goto out;
+               goto out_put_budget;
 
        ret = BLK_STS_RESOURCE;
-       if (!get_device(&sdev->sdev_gendev))
-               goto out;
-
-       if (!scsi_dev_queue_ready(q, sdev))
-               goto out_put_device;
        if (!scsi_target_queue_ready(shost, sdev))
-               goto out_dec_device_busy;
+               goto out_put_budget;
        if (!scsi_host_queue_ready(q, shost, sdev))
                goto out_dec_target_busy;
 
@@ -2002,15 +2018,12 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
        return BLK_STS_OK;
 
 out_dec_host_busy:
-       atomic_dec(&shost->host_busy);
+       atomic_dec(&shost->host_busy);
 out_dec_target_busy:
        if (scsi_target(sdev)->can_queue > 0)
                atomic_dec(&scsi_target(sdev)->target_busy);
-out_dec_device_busy:
-       atomic_dec(&sdev->device_busy);
-out_put_device:
-       put_device(&sdev->sdev_gendev);
-out:
+out_put_budget:
+       scsi_mq_put_budget(hctx);
        switch (ret) {
        case BLK_STS_OK:
                break;
@@ -2214,6 +2227,8 @@ struct request_queue *scsi_old_alloc_queue(struct scsi_device *sdev)
 }
 
 static const struct blk_mq_ops scsi_mq_ops = {
+       .get_budget     = scsi_mq_get_budget,
+       .put_budget     = scsi_mq_put_budget,
        .queue_rq       = scsi_queue_rq,
        .complete       = scsi_softirq_done,
        .timeout        = scsi_timeout,
@@ -2694,7 +2709,6 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 
        }
        sdev->sdev_state = state;
-       sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
        return 0;
 
  illegal:
@@ -2933,21 +2947,37 @@ static void scsi_wait_for_queuecommand(struct scsi_device *sdev)
 int
 scsi_device_quiesce(struct scsi_device *sdev)
 {
+       struct request_queue *q = sdev->request_queue;
        int err;
 
+       /*
+        * It is allowed to call scsi_device_quiesce() multiple times from
+        * the same context but concurrent scsi_device_quiesce() calls are
+        * not allowed.
+        */
+       WARN_ON_ONCE(sdev->quiesced_by && sdev->quiesced_by != current);
+
+       blk_set_preempt_only(q);
+
+       blk_mq_freeze_queue(q);
+       /*
+        * Ensure that the effect of blk_set_preempt_only() will be visible
+        * for percpu_ref_tryget() callers that occur after the queue
+        * unfreeze even if the queue was already frozen before this function
+        * was called. See also https://lwn.net/Articles/573497/.
+        */
+       synchronize_rcu();
+       blk_mq_unfreeze_queue(q);
+
        mutex_lock(&sdev->state_mutex);
        err = scsi_device_set_state(sdev, SDEV_QUIESCE);
+       if (err == 0)
+               sdev->quiesced_by = current;
+       else
+               blk_clear_preempt_only(q);
        mutex_unlock(&sdev->state_mutex);
 
-       if (err)
-               return err;
-
-       scsi_run_queue(sdev->request_queue);
-       while (atomic_read(&sdev->device_busy)) {
-               msleep_interruptible(200);
-               scsi_run_queue(sdev->request_queue);
-       }
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL(scsi_device_quiesce);
 
@@ -2967,9 +2997,11 @@ void scsi_device_resume(struct scsi_device *sdev)
         * device deleted during suspend)
         */
        mutex_lock(&sdev->state_mutex);
-       if (sdev->sdev_state == SDEV_QUIESCE &&
-           scsi_device_set_state(sdev, SDEV_RUNNING) == 0)
-               scsi_run_queue(sdev->request_queue);
+       WARN_ON_ONCE(!sdev->quiesced_by);
+       sdev->quiesced_by = NULL;
+       blk_clear_preempt_only(sdev->request_queue);
+       if (sdev->sdev_state == SDEV_QUIESCE)
+               scsi_device_set_state(sdev, SDEV_RUNNING);
        mutex_unlock(&sdev->state_mutex);
 }
 EXPORT_SYMBOL(scsi_device_resume);
@@ -3122,7 +3154,6 @@ int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
        case SDEV_BLOCK:
        case SDEV_TRANSPORT_OFFLINE:
                sdev->sdev_state = new_state;
-               sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
                break;
        case SDEV_CREATED_BLOCK:
                if (new_state == SDEV_TRANSPORT_OFFLINE ||
@@ -3130,7 +3161,6 @@ int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
                        sdev->sdev_state = new_state;
                else
                        sdev->sdev_state = SDEV_CREATED;
-               sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
                break;
        case SDEV_CANCEL:
        case SDEV_OFFLINE: