]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/scsi_lib.c
scsi: Implement blk_mq_ops.show_rq()
[karo-tx-linux.git] / drivers / scsi / scsi_lib.c
index 3e32dc954c3c8c6b05d5883615afc1b21864e401..91455dabbfefa7fcbfa97f2b313c0f0846b94a30 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <trace/events/scsi.h>
 
+#include "scsi_debugfs.h"
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
@@ -213,10 +214,30 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
        __scsi_queue_insert(cmd, reason, 1);
 }
 
-static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+
+/**
+ * scsi_execute - insert request and wait for the result
+ * @sdev:      scsi device
+ * @cmd:       scsi command
+ * @data_direction: data direction
+ * @buffer:    data buffer
+ * @bufflen:   len of buffer
+ * @sense:     optional sense buffer
+ * @sshdr:     optional decoded sense header
+ * @timeout:   request timeout in seconds
+ * @retries:   number of times to retry request
+ * @flags:     flags for ->cmd_flags
+ * @rq_flags:  flags for ->rq_flags
+ * @resid:     optional residual length
+ *
+ * Returns the scsi_cmnd result field if a command was executed, or a negative
+ * Linux error code if we didn't get that far.
+ */
+int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
-                unsigned char *sense, int timeout, int retries, u64 flags,
-                req_flags_t rq_flags, int *resid)
+                unsigned char *sense, struct scsi_sense_hdr *sshdr,
+                int timeout, int retries, u64 flags, req_flags_t rq_flags,
+                int *resid)
 {
        struct request *req;
        struct scsi_request *rq;
@@ -236,7 +257,7 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 
        rq->cmd_len = COMMAND_SIZE(cmd[0]);
        memcpy(rq->cmd, cmd, rq->cmd_len);
-       req->retries = retries;
+       rq->retries = retries;
        req->timeout = timeout;
        req->cmd_flags |= flags;
        req->rq_flags |= rq_flags | RQF_QUIET | RQF_PREEMPT;
@@ -259,62 +280,16 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                *resid = rq->resid_len;
        if (sense && rq->sense_len)
                memcpy(sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
-       ret = req->errors;
+       if (sshdr)
+               scsi_normalize_sense(rq->sense, rq->sense_len, sshdr);
+       ret = rq->result;
  out:
        blk_put_request(req);
 
        return ret;
 }
-
-/**
- * scsi_execute - insert request and wait for the result
- * @sdev:      scsi device
- * @cmd:       scsi command
- * @data_direction: data direction
- * @buffer:    data buffer
- * @bufflen:   len of buffer
- * @sense:     optional sense buffer
- * @timeout:   request timeout in seconds
- * @retries:   number of times to retry request
- * @flags:     or into request flags;
- * @resid:     optional residual length
- *
- * returns the req->errors value which is the scsi_cmnd result
- * field.
- */
-int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
-                int data_direction, void *buffer, unsigned bufflen,
-                unsigned char *sense, int timeout, int retries, u64 flags,
-                int *resid)
-{
-       return __scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense,
-                       timeout, retries, flags, 0, resid);
-}
 EXPORT_SYMBOL(scsi_execute);
 
-int scsi_execute_req_flags(struct scsi_device *sdev, const unsigned char *cmd,
-                    int data_direction, void *buffer, unsigned bufflen,
-                    struct scsi_sense_hdr *sshdr, int timeout, int retries,
-                    int *resid, u64 flags, req_flags_t rq_flags)
-{
-       char *sense = NULL;
-       int result;
-       
-       if (sshdr) {
-               sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
-               if (!sense)
-                       return DRIVER_ERROR << 24;
-       }
-       result = __scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
-                             sense, timeout, retries, flags, rq_flags, resid);
-       if (sshdr)
-               scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
-
-       kfree(sense);
-       return result;
-}
-EXPORT_SYMBOL(scsi_execute_req_flags);
-
 /*
  * Function:    scsi_init_cmd_errh()
  *
@@ -522,7 +497,7 @@ static void scsi_run_queue(struct request_queue *q)
                scsi_starved_list_run(sdev->host);
 
        if (q->mq_ops)
-               blk_mq_start_stopped_hw_queues(q, false);
+               blk_mq_run_hw_queues(q, false);
        else
                blk_run_queue(q);
 }
@@ -693,7 +668,7 @@ static bool scsi_end_request(struct request *req, int error,
                    !list_empty(&sdev->host->starved_list))
                        kblockd_schedule_work(&sdev->requeue_work);
                else
-                       blk_mq_start_stopped_hw_queues(q, true);
+                       blk_mq_run_hw_queues(q, true);
        } else {
                unsigned long flags;
 
@@ -823,8 +798,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                /*
                 * __scsi_error_from_host_byte may have reset the host_byte
                 */
-               req->errors = cmd->result;
-
+               scsi_req(req)->result = cmd->result;
                scsi_req(req)->resid_len = scsi_get_resid(cmd);
 
                if (scsi_bidi_cmnd(cmd)) {
@@ -861,7 +835,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
        /*
         * Recovered errors need reporting, but they're always treated as
         * success, so fiddle the result code here.  For passthrough requests
-        * we already took a copy of the original into rq->errors which
+        * we already took a copy of the original into sreq->result which
         * is what gets returned to the user
         */
        if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) {
@@ -1203,7 +1177,7 @@ static int scsi_setup_scsi_cmnd(struct scsi_device *sdev, struct request *req)
        cmd->cmd_len = scsi_req(req)->cmd_len;
        cmd->cmnd = scsi_req(req)->cmd;
        cmd->transfersize = blk_rq_bytes(req);
-       cmd->allowed = req->retries;
+       cmd->allowed = scsi_req(req)->retries;
        return BLKPREP_OK;
 }
 
@@ -1307,7 +1281,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
        switch (ret) {
        case BLKPREP_KILL:
        case BLKPREP_INVALID:
-               req->errors = DID_NO_CONNECT << 16;
+               scsi_req(req)->result = DID_NO_CONNECT << 16;
                /* release the command and kill it */
                if (req->special) {
                        struct scsi_cmnd *cmd = req->special;
@@ -1931,7 +1905,7 @@ static int scsi_mq_prep_fn(struct request *req)
 static void scsi_mq_done(struct scsi_cmnd *cmd)
 {
        trace_scsi_dispatch_cmd_done(cmd);
-       blk_mq_complete_request(cmd->request, cmd->request->errors);
+       blk_mq_complete_request(cmd->request);
 }
 
 static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
@@ -2000,7 +1974,7 @@ out:
        case BLK_MQ_RQ_QUEUE_BUSY:
                if (atomic_read(&sdev->device_busy) == 0 &&
                    !scsi_device_blocked(sdev))
-                       blk_mq_delay_queue(hctx, SCSI_QUEUE_DELAY);
+                       blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY);
                break;
        case BLK_MQ_RQ_QUEUE_ERROR:
                /*
@@ -2180,10 +2154,13 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
        return q;
 }
 
-static struct blk_mq_ops scsi_mq_ops = {
+static const struct blk_mq_ops scsi_mq_ops = {
        .queue_rq       = scsi_queue_rq,
        .complete       = scsi_softirq_done,
        .timeout        = scsi_timeout,
+#ifdef CONFIG_BLK_DEBUG_FS
+       .show_rq        = scsi_show_rq,
+#endif
        .init_request   = scsi_init_request,
        .exit_request   = scsi_exit_request,
        .map_queues     = scsi_map_queues,
@@ -2231,6 +2208,29 @@ void scsi_mq_destroy_tags(struct Scsi_Host *shost)
        blk_mq_free_tag_set(&shost->tag_set);
 }
 
+/**
+ * scsi_device_from_queue - return sdev associated with a request_queue
+ * @q: The request queue to return the sdev from
+ *
+ * Return the sdev associated with a request queue or NULL if the
+ * request_queue does not reference a SCSI device.
+ */
+struct scsi_device *scsi_device_from_queue(struct request_queue *q)
+{
+       struct scsi_device *sdev = NULL;
+
+       if (q->mq_ops) {
+               if (q->mq_ops == &scsi_mq_ops)
+                       sdev = q->queuedata;
+       } else if (q->request_fn == scsi_request_fn)
+               sdev = q->queuedata;
+       if (!sdev || !get_device(&sdev->sdev_gendev))
+               sdev = NULL;
+
+       return sdev;
+}
+EXPORT_SYMBOL_GPL(scsi_device_from_queue);
+
 /*
  * Function:    scsi_block_requests()
  *
@@ -2497,28 +2497,20 @@ EXPORT_SYMBOL(scsi_mode_sense);
  *     @sdev:  scsi device to change the state of.
  *     @timeout: command timeout
  *     @retries: number of retries before failing
- *     @sshdr_external: Optional pointer to struct scsi_sense_hdr for
- *             returning sense. Make sure that this is cleared before passing
- *             in.
+ *     @sshdr: outpout pointer for decoded sense information.
  *
  *     Returns zero if unsuccessful or an error if TUR failed.  For
  *     removable media, UNIT_ATTENTION sets ->changed flag.
  **/
 int
 scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
-                    struct scsi_sense_hdr *sshdr_external)
+                    struct scsi_sense_hdr *sshdr)
 {
        char cmd[] = {
                TEST_UNIT_READY, 0, 0, 0, 0, 0,
        };
-       struct scsi_sense_hdr *sshdr;
        int result;
 
-       if (!sshdr_external)
-               sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
-       else
-               sshdr = sshdr_external;
-
        /* try to eat the UNIT_ATTENTION if there are enough retries */
        do {
                result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
@@ -2529,8 +2521,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
        } while (scsi_sense_valid(sshdr) &&
                 sshdr->sense_key == UNIT_ATTENTION && --retries);
 
-       if (!sshdr_external)
-               kfree(sshdr);
        return result;
 }
 EXPORT_SYMBOL(scsi_test_unit_ready);
@@ -2945,6 +2935,8 @@ EXPORT_SYMBOL(scsi_target_resume);
 /**
  * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state
  * @sdev:      device to block
+ * @wait:      Whether or not to wait until ongoing .queuecommand() /
+ *             .queue_rq() calls have finished.
  *
  * Block request made by scsi lld's to temporarily stop all
  * scsi commands on the specified device. May sleep.
@@ -2962,7 +2954,7 @@ EXPORT_SYMBOL(scsi_target_resume);
  * remove the rport mutex lock and unlock calls from srp_queuecommand().
  */
 int
-scsi_internal_device_block(struct scsi_device *sdev)
+scsi_internal_device_block(struct scsi_device *sdev, bool wait)
 {
        struct request_queue *q = sdev->request_queue;
        unsigned long flags;
@@ -2982,12 +2974,16 @@ scsi_internal_device_block(struct scsi_device *sdev)
         * request queue. 
         */
        if (q->mq_ops) {
-               blk_mq_quiesce_queue(q);
+               if (wait)
+                       blk_mq_quiesce_queue(q);
+               else
+                       blk_mq_stop_hw_queues(q);
        } else {
                spin_lock_irqsave(q->queue_lock, flags);
                blk_stop_queue(q);
                spin_unlock_irqrestore(q->queue_lock, flags);
-               scsi_wait_for_queuecommand(sdev);
+               if (wait)
+                       scsi_wait_for_queuecommand(sdev);
        }
 
        return 0;
@@ -3049,7 +3045,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
 static void
 device_block(struct scsi_device *sdev, void *data)
 {
-       scsi_internal_device_block(sdev);
+       scsi_internal_device_block(sdev, true);
 }
 
 static int