From: David Jeffery <djeffery@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: linux-nvme@lists.infradead.org, linux-scsi@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
"Rafael J . Wysocki" <rafael@kernel.org>,
David Jeffery <djeffery@redhat.com>,
Laurence Oberman <loberman@redhat.com>
Subject: [RFC PATCH 5/6] scsi mid layer support for async command submit
Date: Wed, 7 Feb 2024 13:40:59 -0500 [thread overview]
Message-ID: <20240207184100.18066-6-djeffery@redhat.com> (raw)
In-Reply-To: <20240207184100.18066-1-djeffery@redhat.com>
Create scsi_execute_cmd_nowait to allow asynchronous scsi command submit.
Parts of the code originally in scsi_execute_cmd are shifted into helper
functions used by both scsi_execute_cmd and the new scsi_execute_cmd_nowait.
The scsi_exec_args struct is expanded to contain the fields needed for
the completion and callback for the async path.
Signed-off-by: David Jeffery <djeffery@redhat.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
drivers/scsi/scsi_lib.c | 138 +++++++++++++++++++++++++++++--------
include/scsi/scsi_device.h | 8 +++
2 files changed, 118 insertions(+), 28 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1fb80eae9a63..fe35bc2021e3 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -185,42 +185,37 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
}
/**
- * scsi_execute_cmd - insert request and wait for the result
+ * scsi_execute_init - helper for setting up a scsi_cmnd in a request
* @sdev: scsi_device
* @cmd: scsi command
* @opf: block layer request cmd_flags
- * @buffer: data buffer
- * @bufflen: len of buffer
* @timeout: request timeout in HZ
* @retries: number of times to retry request
- * @args: Optional args. See struct definition for field descriptions
+ * @args: scsi command args
*
- * Returns the scsi_cmnd result field if a command was executed, or a negative
- * Linux error code if we didn't get that far.
+ * Returns a request if successful, or an error pointer if there was a failure.
*/
-int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
- blk_opf_t opf, void *buffer, unsigned int bufflen,
- int timeout, int retries,
- const struct scsi_exec_args *args)
+static struct request *scsi_execute_init(struct scsi_device *sdev,
+ const unsigned char *cmd,
+ blk_opf_t opf,
+ int timeout, int retries,
+ struct scsi_exec_args *args)
{
- static const struct scsi_exec_args default_args;
struct request *req;
struct scsi_cmnd *scmd;
int ret;
- if (!args)
- args = &default_args;
- else if (WARN_ON_ONCE(args->sense &&
- args->sense_len != SCSI_SENSE_BUFFERSIZE))
- return -EINVAL;
+ if (WARN_ON_ONCE(args->sense &&
+ args->sense_len != SCSI_SENSE_BUFFERSIZE))
+ return ERR_PTR(-EINVAL);
req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags);
if (IS_ERR(req))
- return PTR_ERR(req);
+ return req;
- if (bufflen) {
- ret = blk_rq_map_kern(sdev->request_queue, req,
- buffer, bufflen, GFP_NOIO);
+ if (args->bufflen) {
+ ret = blk_rq_map_kern(sdev->request_queue, req, args->buffer,
+ args->bufflen, GFP_NOIO);
if (ret)
goto out;
}
@@ -232,19 +227,27 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
req->timeout = timeout;
req->rq_flags |= RQF_QUIET;
- /*
- * head injection *required* here otherwise quiesce won't work
- */
- blk_execute_rq(req, true);
+ return req;
+out:
+ blk_mq_free_request(req);
+ return ERR_PTR(ret);
+}
+
+static int scsi_execute_uninit(struct request *req,
+ struct scsi_exec_args *args)
+{
+ struct scsi_cmnd *scmd;
+ scmd = blk_mq_rq_to_pdu(req);
/*
* Some devices (USB mass-storage in particular) may transfer
* garbage data together with a residue indicating that the data
* is invalid. Prevent the garbage from being misinterpreted
* and prevent security leaks by zeroing out the excess data.
*/
- if (unlikely(scmd->resid_len > 0 && scmd->resid_len <= bufflen))
- memset(buffer + bufflen - scmd->resid_len, 0, scmd->resid_len);
+ if (unlikely(scmd->resid_len > 0 && scmd->resid_len <= args->bufflen))
+ memset(args->buffer + args->bufflen - scmd->resid_len, 0,
+ scmd->resid_len);
if (args->resid)
*args->resid = scmd->resid_len;
@@ -254,14 +257,93 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len,
args->sshdr);
- ret = scmd->result;
- out:
+ args->result = scmd->result;
+
+ if (args->callback)
+ args->callback(scmd, args);
+
+ return scmd->result;
+}
+
+/**
+ * scsi_execute_cmd - insert request and wait for the result
+ * @sdev: scsi_device
+ * @cmd: scsi command
+ * @opf: block layer request cmd_flags
+ * @buffer: data buffer
+ * @bufflen: len of buffer
+ * @timeout: request timeout in HZ
+ * @retries: number of times to retry request
+ * @args: Optional args. See struct definition for field descriptions
+ *
+ * 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_cmd(struct scsi_device *sdev, const unsigned char *cmd,
+ blk_opf_t opf, void *buffer, unsigned int bufflen,
+ int timeout, int retries,
+ const struct scsi_exec_args *const_args)
+{
+ struct scsi_exec_args args;
+ int ret;
+ struct request *req;
+
+ if (!const_args)
+ memset(&args, 0, sizeof(struct scsi_exec_args));
+ else
+ args = *const_args;
+
+ args.buffer = buffer;
+ args.bufflen = bufflen;
+
+ req = scsi_execute_init(sdev, cmd, opf, timeout, retries, &args);
+
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ /*
+ * head injection *required* here otherwise quiesce won't work
+ */
+ blk_execute_rq(req, true);
+
+ ret = scsi_execute_uninit(req, &args);
+
blk_mq_free_request(req);
return ret;
}
EXPORT_SYMBOL(scsi_execute_cmd);
+
+static enum rq_end_io_ret scsi_execute_cmd_complete(struct request *req,
+ blk_status_t ret)
+{
+ struct scsi_exec_args *args = req->end_io_data;
+
+ scsi_execute_uninit(req, args);
+ return RQ_END_IO_FREE;
+}
+
+int scsi_execute_cmd_nowait(struct scsi_device *sdev, const unsigned char *cmd,
+ blk_opf_t opf, int timeout, int retries,
+ struct scsi_exec_args *args)
+{
+ struct request *req;
+
+ req = scsi_execute_init(sdev, cmd, opf, timeout, retries, args);
+
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ req->end_io = scsi_execute_cmd_complete;
+ req->end_io_data = args;
+
+ blk_execute_rq_nowait(req, true);
+
+ return 0;
+}
+EXPORT_SYMBOL(scsi_execute_cmd_nowait);
+
/*
* Wake up the error handler if necessary. Avoid as follows that the error
* handler is not woken up if host in-flight requests number ==
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 5ec1e71a09de..c80c98b48bc1 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -497,6 +497,10 @@ struct scsi_exec_args {
blk_mq_req_flags_t req_flags; /* BLK_MQ_REQ flags */
int scmd_flags; /* SCMD flags */
int *resid; /* residual length */
+ void *buffer; /* data buffer */
+ unsigned int bufflen; /* buffer length */
+ int result; /* scsi layer result */
+ void (*callback)(struct scsi_cmnd *scmd, struct scsi_exec_args *args);
};
int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
@@ -504,6 +508,10 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
int timeout, int retries,
const struct scsi_exec_args *args);
+int scsi_execute_cmd_nowait(struct scsi_device *sdev, const unsigned char *cmd,
+ blk_opf_t opf, int timeout, int retries,
+ struct scsi_exec_args *args);
+
extern void sdev_disable_disk_events(struct scsi_device *sdev);
extern void sdev_enable_disk_events(struct scsi_device *sdev);
extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
--
2.43.0
next prev parent reply other threads:[~2024-02-07 18:42 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-07 18:40 [RFC PATCH 0/6] async device shutdown support David Jeffery
2024-02-07 18:40 ` [RFC PATCH 1/6] minimal async shutdown infrastructure David Jeffery
2024-02-14 3:42 ` Saravana Kannan
2024-02-14 20:55 ` David Jeffery
2024-02-07 18:40 ` [RFC PATCH 2/6] Improve ability to perform async shutdown in parallel David Jeffery
2024-02-07 18:40 ` [RFC PATCH 3/6] pci bus async shutdown support David Jeffery
2024-02-07 18:40 ` [RFC PATCH 4/6] pci nvme " David Jeffery
2024-02-07 18:40 ` David Jeffery [this message]
2024-02-07 18:41 ` [RFC PATCH 6/6] sd: async cache flush on shutdown David Jeffery
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240207184100.18066-6-djeffery@redhat.com \
--to=djeffery@redhat.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=linux-scsi@vger.kernel.org \
--cc=loberman@redhat.com \
--cc=rafael@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®