From d3d1fa2d29bf8b21e454421525b88239a650cf31 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 12 Aug 2009 17:13:26 +0000 Subject: [PATCH] New implementation of the pass-through commands execution. Changes: - scsi_execute_async() renamed to scst_scsi_exec_async() and from now will stay in scst_lib.c - In scst_scsi_exec_async() support for long CDBs and bidirectional commands added - Patches scst_exec_req_fifo were removed for kernels between 2.6.26 and 2.6.29, because they are not needed anymore. Pass-through will work on those kernels without them - Monor bug fixes and cleanups - Docs updated git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1040 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/README | 9 +- scst/include/scst.h | 11 + scst/kernel/scst_exec_req_fifo-2.6.26.patch | 112 ---- scst/kernel/scst_exec_req_fifo-2.6.27.patch | 112 ---- scst/kernel/scst_exec_req_fifo-2.6.28.patch | 112 ---- scst/kernel/scst_exec_req_fifo-2.6.29.patch | 112 ---- scst/kernel/scst_exec_req_fifo-2.6.30.patch | 603 +++++-------------- scst/src/dev_handlers/scst_vdisk.c | 2 +- scst/src/scst_lib.c | 618 +++++++++++--------- scst/src/scst_main.c | 19 +- scst/src/scst_priv.h | 19 +- scst/src/scst_targ.c | 11 +- 12 files changed, 530 insertions(+), 1210 deletions(-) delete mode 100644 scst/kernel/scst_exec_req_fifo-2.6.26.patch delete mode 100644 scst/kernel/scst_exec_req_fifo-2.6.27.patch delete mode 100644 scst/kernel/scst_exec_req_fifo-2.6.28.patch delete mode 100644 scst/kernel/scst_exec_req_fifo-2.6.29.patch diff --git a/scst/README b/scst/README index c6c43521c..07fe51637 100644 --- a/scst/README +++ b/scst/README @@ -63,7 +63,7 @@ them are optional, so, if you don't need the corresponding functionality, you may not apply them. 1. scst_exec_req_fifo-2.6.X.patch. This patch is necessary for -pass-through dev handlers, because in the mainstream kernels +pass-through dev handlers with kernels <2.6.26, because in the them scsi_do_req()/scsi_execute_async() work in LIFO order, instead of expected and required FIFO. So SCST needs new functions scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in the @@ -71,9 +71,10 @@ kernel. This patch does that. You may not patch the kernel if you don't need pass-through support. Alternatively, you can define CONFIG_SCST_STRICT_SERIALIZING compile option during the compilation (see description below). This patch is optional for kernels starting -from 2.6.30. On those kernels pass-through will well work without it. -(Actually, implementation on scsi_async_exec(), which you can find in -scst_lib.c for kernels >=2.6.30, can work on the earlier kernels as +from 2.6.26. On those kernels pass-through will well work without it. +The patch for them created only for the mainline kernel inclusion. +(Actually, implementation on scst_scsi_exec_async(), which you can find +in scst_lib.c for kernels >=2.6.26, can work on the earlier kernels as well, so you're welcome to backport it.) 2. io_context-2.6.X.patch. This patch exports some IO context management diff --git a/scst/include/scst.h b/scst/include/scst.h index b2c6f43de..406d903ba 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -74,6 +74,17 @@ typedef _Bool bool; # define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work) #endif +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + #endif #define SCST_LOCAL_NAME "scst_lcl_drvr" diff --git a/scst/kernel/scst_exec_req_fifo-2.6.26.patch b/scst/kernel/scst_exec_req_fifo-2.6.26.patch deleted file mode 100644 index 882cf7898..000000000 --- a/scst/kernel/scst_exec_req_fifo-2.6.26.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff -upr linux-2.6.26/drivers/scsi/scsi_lib.c linux-2.6.26/drivers/scsi/scsi_lib.c ---- linux-2.6.26/drivers/scsi/scsi_lib.c 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.26/drivers/scsi/scsi_lib.c 2008-07-31 21:20:00.000000000 +0400 -@@ -372,7 +372,7 @@ free_bios: - } - - /** -- * scsi_execute_async - insert request -+ * __scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb -@@ -385,11 +385,14 @@ free_bios: - * @privdata: data passed to done() - * @done: callback function when done - * @gfp: memory allocation flags -+ * @at_head: insert request at head or tail of queue - */ --int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+static inline int __scsi_execute_async(struct scsi_device *sdev, -+ const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries, void *privdata, -- void (*done)(void *, char *, int, int), gfp_t gfp) -+ void (*done)(void *, char *, int, int), gfp_t gfp, -+ int at_head) - { - struct request *req; - struct scsi_io_context *sioc; -@@ -426,7 +429,7 @@ int scsi_execute_async(struct scsi_devic - sioc->data = privdata; - sioc->done = done; - -- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); -+ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async); - return 0; - - free_req: -@@ -435,8 +438,55 @@ free_sense: - kmem_cache_free(scsi_io_context_cache, sioc); - return DRIVER_ERROR << 24; - } -+ -+/** -+ * scsi_execute_async - insert request -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, -+ int retries, void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1); -+} - EXPORT_SYMBOL_GPL(scsi_execute_async); - -+/** -+ * scsi_execute_async_fifo - insert request at tail, in FIFO order -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, int retries, -+ void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0); -+} -+EXPORT_SYMBOL_GPL(scsi_execute_async_fifo); -+ - /* - * Function: scsi_init_cmd_errh() - * -diff -upr linux-2.6.26/include/scsi/scsi_device.h linux-2.6.26/include/scsi/scsi_device.h ---- linux-2.6.26/include/scsi/scsi_device.h 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.26/include/scsi/scsi_device.h 2008-07-31 21:20:39.000000000 +0400 -@@ -333,6 +333,14 @@ extern int scsi_execute_async(struct scs - int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), - gfp_t gfp); -+#define SCSI_EXEC_REQ_FIFO_DEFINED -+extern int scsi_execute_async_fifo(struct scsi_device *sdev, -+ const unsigned char *cmd, int cmd_len, -+ int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, -+ int timeout, int retries, void *privdata, -+ void (*done)(void *, char *, int, int), -+ gfp_t gfp); - - static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) - { diff --git a/scst/kernel/scst_exec_req_fifo-2.6.27.patch b/scst/kernel/scst_exec_req_fifo-2.6.27.patch deleted file mode 100644 index 828121b15..000000000 --- a/scst/kernel/scst_exec_req_fifo-2.6.27.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff -upr linux-2.6.27/drivers/scsi/scsi_lib.c linux-2.6.27/drivers/scsi/scsi_lib.c ---- linux-2.6.27/drivers/scsi/scsi_lib.c 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.27/drivers/scsi/scsi_lib.c 2008-07-31 21:20:00.000000000 +0400 -@@ -372,7 +372,7 @@ free_bios: - } - - /** -- * scsi_execute_async - insert request -+ * __scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb -@@ -385,11 +385,14 @@ free_bios: - * @privdata: data passed to done() - * @done: callback function when done - * @gfp: memory allocation flags -+ * @at_head: insert request at head or tail of queue - */ --int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+static inline int __scsi_execute_async(struct scsi_device *sdev, -+ const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries, void *privdata, -- void (*done)(void *, char *, int, int), gfp_t gfp) -+ void (*done)(void *, char *, int, int), gfp_t gfp, -+ int at_head) - { - struct request *req; - struct scsi_io_context *sioc; -@@ -426,7 +429,7 @@ int scsi_execute_async(struct scsi_devic - sioc->data = privdata; - sioc->done = done; - -- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); -+ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async); - return 0; - - free_req: -@@ -435,8 +438,55 @@ free_sense: - kmem_cache_free(scsi_io_context_cache, sioc); - return DRIVER_ERROR << 24; - } -+ -+/** -+ * scsi_execute_async - insert request -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, -+ int retries, void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1); -+} - EXPORT_SYMBOL_GPL(scsi_execute_async); - -+/** -+ * scsi_execute_async_fifo - insert request at tail, in FIFO order -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, int retries, -+ void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0); -+} -+EXPORT_SYMBOL_GPL(scsi_execute_async_fifo); -+ - /* - * Function: scsi_init_cmd_errh() - * -diff -upr linux-2.6.27/include/scsi/scsi_device.h linux-2.6.27/include/scsi/scsi_device.h ---- linux-2.6.27/include/scsi/scsi_device.h 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.27/include/scsi/scsi_device.h 2008-07-31 21:20:39.000000000 +0400 -@@ -365,6 +365,14 @@ extern int scsi_execute_async(struct scs - int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), - gfp_t gfp); -+#define SCSI_EXEC_REQ_FIFO_DEFINED -+extern int scsi_execute_async_fifo(struct scsi_device *sdev, -+ const unsigned char *cmd, int cmd_len, -+ int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, -+ int timeout, int retries, void *privdata, -+ void (*done)(void *, char *, int, int), -+ gfp_t gfp); - - static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) - { diff --git a/scst/kernel/scst_exec_req_fifo-2.6.28.patch b/scst/kernel/scst_exec_req_fifo-2.6.28.patch deleted file mode 100644 index 076999962..000000000 --- a/scst/kernel/scst_exec_req_fifo-2.6.28.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff -upr linux-2.6.28/drivers/scsi/scsi_lib.c linux-2.6.28/drivers/scsi/scsi_lib.c ---- linux-2.6.28/drivers/scsi/scsi_lib.c 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.28/drivers/scsi/scsi_lib.c 2008-07-31 21:20:00.000000000 +0400 -@@ -380,7 +380,7 @@ free_bios: - } - - /** -- * scsi_execute_async - insert request -+ * __scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb -@@ -393,11 +393,14 @@ free_bios: - * @privdata: data passed to done() - * @done: callback function when done - * @gfp: memory allocation flags -+ * @at_head: insert request at head or tail of queue - */ --int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+static inline int __scsi_execute_async(struct scsi_device *sdev, -+ const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries, void *privdata, -- void (*done)(void *, char *, int, int), gfp_t gfp) -+ void (*done)(void *, char *, int, int), gfp_t gfp, -+ int at_head) - { - struct request *req; - struct scsi_io_context *sioc; -@@ -434,7 +439,7 @@ int scsi_execute_async(struct scsi_devic - sioc->data = privdata; - sioc->done = done; - -- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); -+ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async); - return 0; - - free_req: -@@ -443,8 +446,55 @@ free_sense: - kmem_cache_free(scsi_io_context_cache, sioc); - return DRIVER_ERROR << 24; - } -+ -+/** -+ * scsi_execute_async - insert request -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, -+ int retries, void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1); -+} - EXPORT_SYMBOL_GPL(scsi_execute_async); - -+/** -+ * scsi_execute_async_fifo - insert request at tail, in FIFO order -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, int retries, -+ void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0); -+} -+EXPORT_SYMBOL_GPL(scsi_execute_async_fifo); -+ - /* - * Function: scsi_init_cmd_errh() - * -diff -upr linux-2.6.28/include/scsi/scsi_device.h linux-2.6.28/include/scsi/scsi_device.h ---- linux-2.6.28/include/scsi/scsi_device.h 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.28/include/scsi/scsi_device.h 2008-07-31 21:20:39.000000000 +0400 -@@ -377,6 +377,14 @@ extern int scsi_execute_async(struct scs - int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), - gfp_t gfp); -+#define SCSI_EXEC_REQ_FIFO_DEFINED -+extern int scsi_execute_async_fifo(struct scsi_device *sdev, -+ const unsigned char *cmd, int cmd_len, -+ int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, -+ int timeout, int retries, void *privdata, -+ void (*done)(void *, char *, int, int), -+ gfp_t gfp); - - static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) - { diff --git a/scst/kernel/scst_exec_req_fifo-2.6.29.patch b/scst/kernel/scst_exec_req_fifo-2.6.29.patch deleted file mode 100644 index ceb771e22..000000000 --- a/scst/kernel/scst_exec_req_fifo-2.6.29.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff -upr linux-2.6.29/drivers/scsi/scsi_lib.c linux-2.6.29/drivers/scsi/scsi_lib.c ---- linux-2.6.29/drivers/scsi/scsi_lib.c 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.29/drivers/scsi/scsi_lib.c 2008-07-31 21:20:00.000000000 +0400 -@@ -402,7 +402,7 @@ free_bios: - } - - /** -- * scsi_execute_async - insert request -+ * __scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb -@@ -415,11 +415,14 @@ free_bios: - * @privdata: data passed to done() - * @done: callback function when done - * @gfp: memory allocation flags -+ * @at_head: insert request at head or tail of queue - */ --int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+static inline int __scsi_execute_async(struct scsi_device *sdev, -+ const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries, void *privdata, -- void (*done)(void *, char *, int, int), gfp_t gfp) -+ void (*done)(void *, char *, int, int), gfp_t gfp, -+ int at_head) - { - struct request *req; - struct scsi_io_context *sioc; -@@ -456,7 +461,7 @@ int scsi_execute_async(struct scsi_devic - sioc->data = privdata; - sioc->done = done; - -- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); -+ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async); - return 0; - - free_req: -@@ -465,8 +468,55 @@ free_sense: - kmem_cache_free(scsi_io_context_cache, sioc); - return DRIVER_ERROR << 24; - } -+ -+/** -+ * scsi_execute_async - insert request -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, -+ int retries, void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1); -+} - EXPORT_SYMBOL_GPL(scsi_execute_async); - -+/** -+ * scsi_execute_async_fifo - insert request at tail, in FIFO order -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: data direction -+ * @buffer: data buffer (this can be a kernel buffer or scatterlist) -+ * @bufflen: len of buffer -+ * @use_sg: if buffer is a scatterlist this is the number of elements -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @flags: or into request flags -+ **/ -+int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, int timeout, int retries, -+ void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp) -+{ -+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, -+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0); -+} -+EXPORT_SYMBOL_GPL(scsi_execute_async_fifo); -+ - /* - * Function: scsi_init_cmd_errh() - * -diff -upr linux-2.6.29/include/scsi/scsi_device.h linux-2.6.29/include/scsi/scsi_device.h ---- linux-2.6.29/include/scsi/scsi_device.h 2008-07-14 01:51:29.000000000 +0400 -+++ linux-2.6.29/include/scsi/scsi_device.h 2008-07-31 21:20:39.000000000 +0400 -@@ -376,6 +376,14 @@ extern int scsi_execute_async(struct scs - int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), - gfp_t gfp); -+#define SCSI_EXEC_REQ_FIFO_DEFINED -+extern int scsi_execute_async_fifo(struct scsi_device *sdev, -+ const unsigned char *cmd, int cmd_len, -+ int data_direction, void *buffer, -+ unsigned bufflen, int use_sg, -+ int timeout, int retries, void *privdata, -+ void (*done)(void *, char *, int, int), -+ gfp_t gfp); - - static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) - { diff --git a/scst/kernel/scst_exec_req_fifo-2.6.30.patch b/scst/kernel/scst_exec_req_fifo-2.6.30.patch index f3202542d..aa2a84dc2 100644 --- a/scst/kernel/scst_exec_req_fifo-2.6.30.patch +++ b/scst/kernel/scst_exec_req_fifo-2.6.30.patch @@ -1,6 +1,6 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c --- linux-2.6.30.1/block/blk-map.c 2009-07-10 21:13:25.000000000 +0400 -+++ linux-2.6.30.1/block/blk-map.c 2009-07-14 19:24:36.000000000 +0400 ++++ linux-2.6.30.1/block/blk-map.c 2009-08-12 20:01:43.000000000 +0400 @@ -5,6 +5,7 @@ #include #include @@ -9,181 +9,75 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c #include /* for struct sg_iovec */ #include "blk.h" -@@ -154,7 +155,7 @@ int blk_rq_map_user(struct request_queue - } - - if (!bio_flagged(bio, BIO_USER_MAPPED)) -- rq->cmd_flags |= REQ_COPY_USER; -+ rq->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; - - rq->buffer = rq->data = NULL; - return 0; -@@ -230,7 +231,7 @@ int blk_rq_map_user_iov(struct request_q - } - - if (!bio_flagged(bio, BIO_USER_MAPPED)) -- rq->cmd_flags |= REQ_COPY_USER; -+ rq->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; - - blk_queue_bounce(q, &bio); - bio_get(bio); -@@ -272,6 +273,413 @@ int blk_rq_unmap_user(struct bio *bio) +@@ -272,6 +273,336 @@ int blk_rq_unmap_user(struct bio *bio) } EXPORT_SYMBOL(blk_rq_unmap_user); -+struct blk_kern_sg_hdr { -+ struct scatterlist *orig_sgp; -+ union { -+ struct sg_table new_sg_table; -+ struct scatterlist *saved_sg; -+ }; -+ bool tail_only; ++struct blk_kern_sg_work { ++ atomic_t bios_inflight; ++ struct sg_table sg_table; ++ struct scatterlist *src_sgl; +}; + -+#define BLK_KERN_SG_HDR_ENTRIES (1 + (sizeof(struct blk_kern_sg_hdr) - 1) / \ -+ sizeof(struct scatterlist)) -+ -+/** -+ * blk_rq_unmap_kern_sg - "unmaps" data buffers in the request -+ * @req: request to unmap -+ * @do_copy: sets copy data between buffers, if needed, or not -+ * -+ * Description: -+ * It frees all additional buffers allocated for SG->BIO mapping. -+ */ -+void blk_rq_unmap_kern_sg(struct request *req, int do_copy) ++static void blk_free_kern_sg_work(struct blk_kern_sg_work *bw) +{ -+ struct blk_kern_sg_hdr *hdr = (struct blk_kern_sg_hdr *)req->end_io_data; -+ -+ if (hdr == NULL) -+ goto out; -+ -+ if (hdr->tail_only) { -+ /* Tail element only was copied */ -+ struct scatterlist *saved_sg = hdr->saved_sg; -+ struct scatterlist *tail_sg = hdr->orig_sgp; -+ -+ if ((rq_data_dir(req) == READ) && do_copy) -+ sg_copy_elem(saved_sg, tail_sg, tail_sg->length, -+ KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ); -+ -+ __free_pages(sg_page(tail_sg), get_order(tail_sg->length)); -+ *tail_sg = *saved_sg; -+ kfree(hdr); -+ } else { -+ /* The whole SG was copied */ -+ struct sg_table new_sg_table = hdr->new_sg_table; -+ struct scatterlist *new_sgl = new_sg_table.sgl + -+ BLK_KERN_SG_HDR_ENTRIES; -+ struct scatterlist *orig_sgl = hdr->orig_sgp; -+ -+ if ((rq_data_dir(req) == READ) && do_copy) -+ sg_copy(orig_sgl, new_sgl, 0, KM_BIO_DST_IRQ, -+ KM_BIO_SRC_IRQ); -+ -+ sg_free_table(&new_sg_table); -+ } -+ -+out: ++ sg_free_table(&bw->sg_table); ++ kfree(bw); + return; +} -+EXPORT_SYMBOL(blk_rq_unmap_kern_sg); + -+static int blk_rq_handle_align_tail_only(struct request *rq, -+ struct scatterlist *sg_to_copy, -+ gfp_t gfp, gfp_t page_gfp) ++static void blk_bio_map_kern_endio(struct bio *bio, int err) +{ -+ int res = 0; -+ struct scatterlist *tail_sg = sg_to_copy; -+ struct scatterlist *saved_sg; -+ struct blk_kern_sg_hdr *hdr; -+ int saved_sg_nents; -+ struct page *pg; ++ struct blk_kern_sg_work *bw = bio->bi_private; + -+ saved_sg_nents = 1 + BLK_KERN_SG_HDR_ENTRIES; ++ if (bw != NULL) { ++ /* Decrement the bios in processing and, if zero, free */ ++ BUG_ON(atomic_read(&bw->bios_inflight) <= 0); ++ if (atomic_dec_and_test(&bw->bios_inflight)) { ++ if ((bio_data_dir(bio) == READ) && (err == 0)) { ++ unsigned long flags; + -+ saved_sg = kmalloc(sizeof(*saved_sg) * saved_sg_nents, gfp); -+ if (saved_sg == NULL) -+ goto out_nomem; ++ local_irq_save(flags); /* to protect KMs */ ++ sg_copy(bw->src_sgl, bw->sg_table.sgl, 0, 0, ++ KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ } ++ blk_free_kern_sg_work(bw); ++ } ++ } + -+ sg_init_table(saved_sg, saved_sg_nents); -+ -+ hdr = (struct blk_kern_sg_hdr *)saved_sg; -+ saved_sg += BLK_KERN_SG_HDR_ENTRIES; -+ saved_sg_nents -= BLK_KERN_SG_HDR_ENTRIES; -+ -+ hdr->tail_only = true; -+ hdr->orig_sgp = tail_sg; -+ hdr->saved_sg = saved_sg; -+ -+ *saved_sg = *tail_sg; -+ -+ pg = alloc_pages(page_gfp, get_order(tail_sg->length)); -+ if (pg == NULL) -+ goto err_free_saved_sg; -+ -+ sg_assign_page(tail_sg, pg); -+ tail_sg->offset = 0; -+ -+ if (rq_data_dir(rq) == WRITE) -+ sg_copy_elem(tail_sg, saved_sg, saved_sg->length, -+ KM_USER1, KM_USER0); -+ -+ rq->end_io_data = hdr; -+ rq->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; -+ -+out: -+ return res; -+ -+err_free_saved_sg: -+ kfree(saved_sg); -+ -+out_nomem: -+ res = -ENOMEM; -+ goto out; ++ bio_put(bio); ++ return; +} + -+static int blk_rq_handle_align(struct request *rq, struct scatterlist **psgl, -+ int *pnents, struct scatterlist *sgl_to_copy, -+ int nents_to_copy, gfp_t gfp, gfp_t page_gfp) ++static int blk_rq_copy_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, struct blk_kern_sg_work **pbw, ++ gfp_t gfp, gfp_t page_gfp) +{ + int res = 0, i; -+ struct scatterlist *sgl = *psgl; -+ int nents = *pnents; -+ struct sg_table sg_table; + struct scatterlist *sg; + struct scatterlist *new_sgl; -+ size_t len = 0, to_copy; + int new_sgl_nents; -+ struct blk_kern_sg_hdr *hdr; ++ size_t len = 0, to_copy; ++ struct blk_kern_sg_work *bw; + -+ if (sgl != sgl_to_copy) { -+ /* copy only the last element */ -+ res = blk_rq_handle_align_tail_only(rq, sgl_to_copy, -+ gfp, page_gfp); -+ if (res == 0) -+ goto out; -+ /* else go through */ -+ } ++ bw = kzalloc(sizeof(*bw), gfp); ++ if (bw == NULL) ++ goto out; ++ ++ bw->src_sgl = sgl; + + for_each_sg(sgl, sg, nents, i) + len += sg->length; + to_copy = len; + -+ new_sgl_nents = PFN_UP(len) + BLK_KERN_SG_HDR_ENTRIES; ++ new_sgl_nents = PFN_UP(len); + -+ res = sg_alloc_table(&sg_table, new_sgl_nents, gfp); ++ res = sg_alloc_table(&bw->sg_table, new_sgl_nents, gfp); + if (res != 0) -+ goto out; ++ goto out_free_bw; + -+ new_sgl = sg_table.sgl; -+ hdr = (struct blk_kern_sg_hdr *)new_sgl; -+ new_sgl += BLK_KERN_SG_HDR_ENTRIES; -+ new_sgl_nents -= BLK_KERN_SG_HDR_ENTRIES; -+ -+ hdr->tail_only = false; -+ hdr->orig_sgp = sgl; -+ hdr->new_sg_table = sg_table; ++ new_sgl = bw->sg_table.sgl; + + for_each_sg(new_sgl, sg, new_sgl_nents, i) { + struct page *pg; @@ -201,17 +95,19 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + if (rq_data_dir(rq) == WRITE) { + /* + * We need to limit amount of copied data to to_copy, because -+ * sgl might have the last element not marked as last in ++ * sgl might have the last element in sgl not marked as last in + * SG chaining. + */ -+ sg_copy(new_sgl, sgl, to_copy, KM_USER0, KM_USER1); ++ sg_copy(new_sgl, sgl, 0, to_copy, ++ KM_USER0, KM_USER1); + } + -+ rq->end_io_data = hdr; -+ rq->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; -+ -+ *psgl = new_sgl; -+ *pnents = new_sgl_nents; ++ *pbw = bw; ++ /* ++ * REQ_COPY_USER name is misleading. It should be something like ++ * REQ_HAS_TAIL_SPACE_FOR_PADDING. ++ */ ++ rq->cmd_flags |= REQ_COPY_USER; + +out: + return res; @@ -223,20 +119,16 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + break; + __free_page(pg); + } -+ sg_free_table(&sg_table); ++ sg_free_table(&bw->sg_table); + ++out_free_bw: ++ kfree(bw); + res = -ENOMEM; + goto out; +} + -+static void bio_map_kern_endio(struct bio *bio, int err) -+{ -+ bio_put(bio); -+} -+ +static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, -+ int nents, gfp_t gfp, struct scatterlist **sgl_to_copy, -+ int *nents_to_copy) ++ int nents, struct blk_kern_sg_work *bw, gfp_t gfp) +{ + int res; + struct request_queue *q = rq->q; @@ -246,10 +138,9 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + bool need_new_bio; + struct scatterlist *sg, *prev_sg = NULL; + struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; ++ int bios; + -+ *sgl_to_copy = NULL; -+ -+ if (unlikely((sgl == 0) || (nents <= 0))) { ++ if (unlikely((sgl == NULL) || (sgl->length == 0) || (nents <= 0))) { + WARN_ON(1); + res = -EINVAL; + goto out; @@ -265,6 +156,7 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + + need_new_bio = true; + tot_len = 0; ++ bios = 0; + for_each_sg(sgl, sg, nents, i) { + struct page *page = sg_page(sg); + void *page_addr = page_address(page); @@ -287,7 +179,7 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + if (((sg->offset | l) & queue_dma_alignment(q)) || + (page_addr && object_is_on_stack(page_addr + sg->offset))) { + res = -EINVAL; -+ goto out_need_copy; ++ goto out_free_bios; + } + + while (len > 0) { @@ -304,7 +196,9 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + if (rw == WRITE) + bio->bi_rw |= 1 << BIO_RW; + -+ bio->bi_end_io = bio_map_kern_endio; ++ bios++; ++ bio->bi_private = bw; ++ bio->bi_end_io = blk_bio_map_kern_endio; + + if (hbio == NULL) + hbio = tbio = bio; @@ -321,7 +215,7 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + res = rc; + else + res = -EIO; -+ goto out_need_copy; ++ goto out_free_bios; + } else { + need_new_bio = true; + len -= rc; @@ -344,16 +238,14 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + + /* Total length must be aligned on DMA padding alignment */ + if ((tot_len & q->dma_pad_mask) && -+ !(rq->cmd_flags & REQ_HAS_TAIL_SPACE_FOR_PADDING)) { ++ !(rq->cmd_flags & REQ_COPY_USER)) { + res = -EINVAL; -+ if (sgl->offset == 0) { -+ *sgl_to_copy = prev_sg; -+ *nents_to_copy = 1; -+ goto out_free_bios; -+ } else -+ goto out_need_copy; ++ goto out_free_bios; + } + ++ if (bw != NULL) ++ atomic_set(&bw->bios_inflight, bios); ++ + while (hbio != NULL) { + bio = hbio; + hbio = hbio->bi_next; @@ -365,19 +257,15 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + if (unlikely(res != 0)) { + bio->bi_next = hbio; + hbio = bio; -+ goto out_free_bios; ++ /* We can have one or more bios bounced */ ++ goto out_unmap_bios; + } + } + + rq->buffer = rq->data = NULL; -+ +out: + return res; + -+out_need_copy: -+ *sgl_to_copy = sgl; -+ *nents_to_copy = nents; -+ +out_free_bios: + while (hbio != NULL) { + bio = hbio; @@ -385,6 +273,10 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + bio_put(bio); + } + goto out; ++ ++out_unmap_bios: ++ blk_rq_unmap_kern_sg(rq, res); ++ goto out; +} + +/** @@ -402,31 +294,20 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + int nents, gfp_t gfp) +{ + int res; -+ struct scatterlist *sg_to_copy = NULL; -+ int nents_to_copy = 0; + -+ if (unlikely((sgl == 0) || (sgl->length == 0) || -+ (nents <= 0) || (rq->end_io_data != NULL))) { -+ WARN_ON(1); -+ res = -EINVAL; -+ goto out; -+ } -+ -+ res = __blk_rq_map_kern_sg(rq, sgl, nents, gfp, &sg_to_copy, -+ &nents_to_copy); ++ res = __blk_rq_map_kern_sg(rq, sgl, nents, NULL, gfp); + if (unlikely(res != 0)) { -+ if (sg_to_copy == NULL) -+ goto out; ++ struct blk_kern_sg_work *bw = NULL; + -+ res = blk_rq_handle_align(rq, &sgl, &nents, sg_to_copy, -+ nents_to_copy, gfp, rq->q->bounce_gfp | gfp); ++ res = blk_rq_copy_kern_sg(rq, sgl, nents, &bw, ++ gfp, rq->q->bounce_gfp | gfp); + if (unlikely(res != 0)) + goto out; + -+ res = __blk_rq_map_kern_sg(rq, sgl, nents, gfp, &sg_to_copy, -+ &nents_to_copy); ++ res = __blk_rq_map_kern_sg(rq, bw->sg_table.sgl, ++ bw->sg_table.nents, bw, gfp); + if (res != 0) { -+ blk_rq_unmap_kern_sg(rq, 0); ++ blk_free_kern_sg_work(bw); + goto out; + } + } @@ -437,250 +318,82 @@ diff -upkr linux-2.6.30.1/block/blk-map.c linux-2.6.30.1/block/blk-map.c + return res; +} +EXPORT_SYMBOL(blk_rq_map_kern_sg); ++ ++/** ++ * blk_rq_unmap_kern_sg - unmap a request with kernel sg ++ * @rq: request to unmap ++ * @err: non-zero error code ++ * ++ * Description: ++ * Unmap a rq previously mapped by blk_rq_map_kern_sg(). Must be called ++ * only in case of an error! ++ */ ++void blk_rq_unmap_kern_sg(struct request *rq, int err) ++{ ++ struct bio *bio = rq->bio; ++ ++ while (bio) { ++ struct bio *b = bio; ++ bio = bio->bi_next; ++ b->bi_end_io(b, err); ++ } ++ rq->bio = 0; ++ ++ return; ++} ++EXPORT_SYMBOL(blk_rq_unmap_kern_sg); + /** * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage * @q: request queue where request should be inserted -@@ -309,7 +717,7 @@ int blk_rq_map_kern(struct request_queue - bio->bi_rw |= (1 << BIO_RW); - - if (do_copy) -- rq->cmd_flags |= REQ_COPY_USER; -+ rq->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; - - blk_rq_bio_prep(q, rq, bio); - blk_queue_bounce(q, &rq->bio); -diff -upkr linux-2.6.30.1/block/blk-merge.c linux-2.6.30.1/block/blk-merge.c ---- linux-2.6.30.1/block/blk-merge.c 2009-07-10 21:13:25.000000000 +0400 -+++ linux-2.6.30.1/block/blk-merge.c 2009-07-08 21:24:29.000000000 +0400 -@@ -198,7 +198,7 @@ new_segment: - } /* segments in rq */ - - -- if (unlikely(rq->cmd_flags & REQ_COPY_USER) && -+ if ((rq->cmd_flags & REQ_HAS_TAIL_SPACE_FOR_PADDING) && - (rq->data_len & q->dma_pad_mask)) { - unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1; - -diff -upkr linux-2.6.30.1/drivers/scsi/scsi_lib.c linux-2.6.30.1/drivers/scsi/scsi_lib.c ---- linux-2.6.30.1/drivers/scsi/scsi_lib.c 2009-07-10 21:13:25.000000000 +0400 -+++ linux-2.6.30.1/drivers/scsi/scsi_lib.c 2009-07-08 21:24:29.000000000 +0400 -@@ -277,6 +277,100 @@ int scsi_execute_req(struct scsi_device - } - EXPORT_SYMBOL(scsi_execute_req); - -+struct scsi_io_context { -+ void *blk_data; -+ void *data; -+ void (*done)(void *data, char *sense, int result, int resid); -+ char sense[SCSI_SENSE_BUFFERSIZE]; -+}; -+ -+static struct kmem_cache *scsi_io_context_cache; -+ -+static void scsi_end_async(struct request *req, int error) -+{ -+ struct scsi_io_context *sioc = req->end_io_data; -+ -+ req->end_io_data = sioc->blk_data; -+ blk_rq_unmap_kern_sg(req, (error == 0)); -+ -+ if (sioc->done) -+ sioc->done(sioc->data, sioc->sense, req->errors, req->data_len); -+ -+ kmem_cache_free(scsi_io_context_cache, sioc); -+ __blk_put_request(req->q, req); -+} -+ -+/** -+ * scsi_execute_async - insert request -+ * @sdev: scsi device -+ * @cmd: scsi command -+ * @cmd_len: length of scsi cdb -+ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE -+ * @sgl: data buffer scatterlist -+ * @nents: number of elements in the sgl -+ * @timeout: request timeout in seconds -+ * @retries: number of times to retry request -+ * @privdata: data passed to done() -+ * @done: callback function when done -+ * @gfp: memory allocation flags -+ * @flags: one or more SCSI_ASYNC_EXEC_FLAG_* flags -+ */ -+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, struct scatterlist *sgl, -+ int nents, int timeout, int retries, void *privdata, -+ void (*done)(void *, char *, int, int), gfp_t gfp, -+ int flags) -+{ -+ struct request *req; -+ struct scsi_io_context *sioc; -+ int err = 0; -+ int write = (data_direction == DMA_TO_DEVICE); -+ -+ sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp); -+ if (sioc == NULL) -+ return DRIVER_ERROR << 24; -+ -+ req = blk_get_request(sdev->request_queue, write, gfp); -+ if (req == NULL) -+ goto free_sense; -+ req->cmd_type = REQ_TYPE_BLOCK_PC; -+ req->cmd_flags |= REQ_QUIET; -+ -+ if (flags & SCSI_ASYNC_EXEC_FLAG_HAS_TAIL_SPACE_FOR_PADDING) -+ req->cmd_flags |= REQ_HAS_TAIL_SPACE_FOR_PADDING; -+ -+ if (sgl != NULL) { -+ err = blk_rq_map_kern_sg(req, sgl, nents, gfp); -+ if (err) -+ goto free_req; -+ } -+ -+ sioc->blk_data = req->end_io_data; -+ sioc->data = privdata; -+ sioc->done = done; -+ -+ req->cmd_len = cmd_len; -+ memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ -+ memcpy(req->cmd, cmd, req->cmd_len); -+ req->sense = sioc->sense; -+ req->sense_len = 0; -+ req->timeout = timeout; -+ req->retries = retries; -+ req->end_io_data = sioc; -+ -+ blk_execute_rq_nowait(req->q, NULL, req, -+ flags & SCSI_ASYNC_EXEC_FLAG_AT_HEAD, scsi_end_async); -+ return 0; -+ -+free_req: -+ blk_put_request(req); -+ -+free_sense: -+ kmem_cache_free(scsi_io_context_cache, sioc); -+ return DRIVER_ERROR << 24; -+} -+EXPORT_SYMBOL_GPL(scsi_execute_async); -+ - /* - * Function: scsi_init_cmd_errh() - * -@@ -1743,12 +1837,20 @@ int __init scsi_init_queue(void) - { - int i; - -+ scsi_io_context_cache = kmem_cache_create("scsi_io_context", -+ sizeof(struct scsi_io_context), -+ 0, 0, NULL); -+ if (!scsi_io_context_cache) { -+ printk(KERN_ERR "SCSI: can't init scsi io context cache\n"); -+ return -ENOMEM; -+ } -+ - scsi_sdb_cache = kmem_cache_create("scsi_data_buffer", - sizeof(struct scsi_data_buffer), - 0, 0, NULL); - if (!scsi_sdb_cache) { - printk(KERN_ERR "SCSI: can't init scsi sdb cache\n"); -- return -ENOMEM; -+ goto cleanup_io_context; - } - - for (i = 0; i < SG_MEMPOOL_NR; i++) { -@@ -1784,6 +1886,9 @@ cleanup_sdb: - } - kmem_cache_destroy(scsi_sdb_cache); - -+cleanup_io_context: -+ kmem_cache_destroy(scsi_io_context_cache); -+ - return -ENOMEM; - } - -@@ -1791,6 +1896,7 @@ void scsi_exit_queue(void) - { - int i; - -+ kmem_cache_destroy(scsi_io_context_cache); - kmem_cache_destroy(scsi_sdb_cache); - - for (i = 0; i < SG_MEMPOOL_NR; i++) { diff -upkr linux-2.6.30.1/include/linux/blkdev.h linux-2.6.30.1/include/linux/blkdev.h --- linux-2.6.30.1/include/linux/blkdev.h 2009-07-10 21:13:25.000000000 +0400 -+++ linux-2.6.30.1/include/linux/blkdev.h 2009-07-13 13:56:45.000000000 +0400 -@@ -115,7 +115,7 @@ enum rq_flag_bits { - __REQ_RW_SYNC, /* request is sync (sync write or read) */ - __REQ_ALLOCED, /* request came from our alloc pool */ - __REQ_RW_META, /* metadata io request */ -- __REQ_COPY_USER, /* contains copies of user pages */ -+ __REQ_HAS_TAIL_SPACE_FOR_PADDING, /* has space for padding in the tail */ - __REQ_INTEGRITY, /* integrity metadata has been remapped */ - __REQ_NOIDLE, /* Don't anticipate more IO after this one */ - __REQ_IO_STAT, /* account I/O stat */ -@@ -143,7 +143,7 @@ enum rq_flag_bits { - #define REQ_RW_SYNC (1 << __REQ_RW_SYNC) - #define REQ_ALLOCED (1 << __REQ_ALLOCED) - #define REQ_RW_META (1 << __REQ_RW_META) --#define REQ_COPY_USER (1 << __REQ_COPY_USER) -+#define REQ_HAS_TAIL_SPACE_FOR_PADDING (1 << __REQ_HAS_TAIL_SPACE_FOR_PADDING) - #define REQ_INTEGRITY (1 << __REQ_INTEGRITY) - #define REQ_NOIDLE (1 << __REQ_NOIDLE) - #define REQ_IO_STAT (1 << __REQ_IO_STAT) -@@ -807,6 +807,9 @@ extern int blk_rq_map_kern(struct reques ++++ linux-2.6.30.1/include/linux/blkdev.h 2009-08-12 19:48:06.000000000 +0400 +@@ -704,6 +704,8 @@ extern unsigned long blk_max_low_pfn, bl + #define BLK_DEFAULT_SG_TIMEOUT (60 * HZ) + #define BLK_MIN_SG_TIMEOUT (7 * HZ) + ++#define SCSI_EXEC_REQ_FIFO_DEFINED ++ + #ifdef CONFIG_BOUNCE + extern int init_emergency_isa_pool(void); + extern void blk_queue_bounce(struct request_queue *q, struct bio **bio); +@@ -807,6 +809,9 @@ extern int blk_rq_map_kern(struct reques extern int blk_rq_map_user_iov(struct request_queue *, struct request *, struct rq_map_data *, struct sg_iovec *, int, unsigned int, gfp_t); -+extern int blk_rq_map_kern_sg(struct request *rq, -+ struct scatterlist *sgl, int nents, gfp_t gfp); -+extern void blk_rq_unmap_kern_sg(struct request *req, int do_copy); ++extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, gfp_t gfp); ++extern void blk_rq_unmap_kern_sg(struct request *rq, int err); extern int blk_execute_rq(struct request_queue *, struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, diff -upkr linux-2.6.30.1/include/linux/scatterlist.h linux-2.6.30.1/include/linux/scatterlist.h --- linux-2.6.30.1/include/linux/scatterlist.h 2009-06-10 07:05:27.000000000 +0400 -+++ linux-2.6.30.1/include/linux/scatterlist.h 2009-07-13 13:56:24.000000000 +0400 -@@ -218,6 +218,15 @@ size_t sg_copy_from_buffer(struct scatte ++++ linux-2.6.30.1/include/linux/scatterlist.h 2009-08-12 19:50:02.000000000 +0400 +@@ -3,6 +3,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, size_t buflen); -+enum km_type; -+ -+int sg_copy_elem(struct scatterlist *dst_sg, struct scatterlist *src_sg, -+ size_t copy_len, enum km_type d_km_type, -+ enum km_type s_km_type); -+int sg_copy(struct scatterlist *dst_sg, -+ struct scatterlist *src_sg, size_t copy_len, ++int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, ++ int nents_to_copy, size_t copy_len, + enum km_type d_km_type, enum km_type s_km_type); + /* * Maximum number of entries that will be allocated in one piece, if * a list larger than this is required then chaining will be utilized. -diff -upkr linux-2.6.30.1/include/scsi/scsi_device.h linux-2.6.30.1/include/scsi/scsi_device.h ---- linux-2.6.30.1/include/scsi/scsi_device.h 2009-07-10 21:13:25.000000000 +0400 -+++ linux-2.6.30.1/include/scsi/scsi_device.h 2009-07-08 21:24:29.000000000 +0400 -@@ -372,6 +372,17 @@ extern int scsi_execute_req(struct scsi_ - struct scsi_sense_hdr *, int timeout, int retries, - int *resid); - -+#define SCSI_ASYNC_EXEC_FLAG_AT_HEAD 1 -+#define SCSI_ASYNC_EXEC_FLAG_HAS_TAIL_SPACE_FOR_PADDING 2 -+ -+#define SCSI_EXEC_REQ_FIFO_DEFINED -+extern int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, -+ int cmd_len, int data_direction, -+ struct scatterlist *sgl, int nents, int timeout, -+ int retries, void *privdata, -+ void (*done)(void *, char *, int, int), -+ gfp_t gfp, int flags); -+ - static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) - { - return device_reprobe(&sdev->sdev_gendev); diff -upkr linux-2.6.30.1/lib/scatterlist.c linux-2.6.30.1/lib/scatterlist.c --- linux-2.6.30.1/lib/scatterlist.c 2009-06-10 07:05:27.000000000 +0400 -+++ linux-2.6.30.1/lib/scatterlist.c 2009-07-14 19:22:49.000000000 +0400 -@@ -485,3 +485,150 @@ size_t sg_copy_to_buffer(struct scatterl ++++ linux-2.6.30.1/lib/scatterlist.c 2009-08-12 19:56:04.000000000 +0400 +@@ -485,3 +485,132 @@ size_t sg_copy_to_buffer(struct scatterl return sg_copy_buffer(sgl, nents, buf, buflen, 1); } EXPORT_SYMBOL(sg_copy_to_buffer); @@ -690,19 +403,16 @@ diff -upkr linux-2.6.30.1/lib/scatterlist.c linux-2.6.30.1/lib/scatterlist.c + * one dst_sg element, it must be either last in the chain, or + * copy_len == dst_sg->length. + */ -+static int __sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len, -+ size_t *pdst_offs, struct scatterlist *src_sg, -+ size_t copy_len, -+ enum km_type d_km_type, enum km_type s_km_type) ++static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len, ++ size_t *pdst_offs, struct scatterlist *src_sg, ++ size_t copy_len, ++ enum km_type d_km_type, enum km_type s_km_type) +{ + int res = 0; + struct scatterlist *dst_sg; + size_t src_len, dst_len, src_offs, dst_offs; + struct page *src_page, *dst_page; + -+ if (copy_len == 0) -+ copy_len = 0x7FFFFFFF; /* copy all */ -+ + dst_sg = *pdst_sg; + dst_len = *pdst_len; + dst_offs = *pdst_offs; @@ -768,34 +478,10 @@ diff -upkr linux-2.6.30.1/lib/scatterlist.c linux-2.6.30.1/lib/scatterlist.c +} + +/** -+ * sg_copy_elem - copy one SG element to another -+ * @dst_sg: destination SG element -+ * @src_sg: source SG element -+ * @copy_len: maximum amount of data to copy. If 0, then copy all. -+ * @d_km_type: kmap_atomic type for the destination SG -+ * @s_km_type: kmap_atomic type for the source SG -+ * -+ * Description: -+ * Data from the source SG element will be copied to the destination SG -+ * element. Returns number of bytes copied. Can switch to the next dst_sg -+ * element, so, to copy to strictly only one dst_sg element, it must be -+ * either last in the chain, or copy_len == dst_sg->length. -+ */ -+int sg_copy_elem(struct scatterlist *dst_sg, struct scatterlist *src_sg, -+ size_t copy_len, enum km_type d_km_type, -+ enum km_type s_km_type) -+{ -+ size_t dst_len = dst_sg->length, dst_offs = dst_sg->offset; -+ -+ return __sg_copy_elem(&dst_sg, &dst_len, &dst_offs, src_sg, -+ copy_len, d_km_type, s_km_type); -+} -+EXPORT_SYMBOL(sg_copy_elem); -+ -+/** + * sg_copy - copy one SG vector to another + * @dst_sg: destination SG + * @src_sg: source SG ++ * @nents_to_copy: maximum number of entries to copy + * @copy_len: maximum amount of data to copy. If 0, then copy all. + * @d_km_type: kmap_atomic type for the destination SG + * @s_km_type: kmap_atomic type for the source SG @@ -805,8 +491,8 @@ diff -upkr linux-2.6.30.1/lib/scatterlist.c linux-2.6.30.1/lib/scatterlist.c + * vector. End of the vectors will be determined by sg_next() returning + * NULL. Returns number of bytes copied. + */ -+int sg_copy(struct scatterlist *dst_sg, -+ struct scatterlist *src_sg, size_t copy_len, ++int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, ++ int nents_to_copy, size_t copy_len, + enum km_type d_km_type, enum km_type s_km_type) +{ + int res = 0; @@ -815,15 +501,24 @@ diff -upkr linux-2.6.30.1/lib/scatterlist.c linux-2.6.30.1/lib/scatterlist.c + if (copy_len == 0) + copy_len = 0x7FFFFFFF; /* copy all */ + ++ if (nents_to_copy == 0) ++ nents_to_copy = 0x7FFFFFFF; /* copy all */ ++ + dst_len = dst_sg->length; + dst_offs = dst_sg->offset; + + do { -+ copy_len -= __sg_copy_elem(&dst_sg, &dst_len, &dst_offs, ++ int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs, + src_sg, copy_len, d_km_type, s_km_type); ++ copy_len -= copied; ++ res += copied; + if ((copy_len == 0) || (dst_sg == NULL)) + goto out; + ++ nents_to_copy--; ++ if (nents_to_copy == 0) ++ goto out; ++ + src_sg = sg_next(src_sg); + } while (src_sg != NULL); + diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 369a49e64..10eb2688c 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -2483,7 +2483,7 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, #endif if (!bio) { PRINT_ERROR("Failed to create bio " - "for data segment= %d cmd %p", + "for data segment %d (cmd %p)", cmd->get_sg_buf_entry_num, cmd); goto out_no_bio; } diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index bb0274ac9..c7319f3f2 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -35,6 +35,17 @@ #include "scst_cdbprobe.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +struct scsi_io_context { + unsigned int full_cdb_used:1; + void *data; + void (*done)(void *data, char *sense, int result, int resid); + char sense[SCST_SENSE_BUFFERSIZE]; + unsigned char full_cdb[0]; +}; +static struct kmem_cache *scsi_io_context_cache; +#endif + static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev); static void scst_check_internal_sense(struct scst_device *dev, int result, uint8_t *sense, int sense_len); @@ -2781,26 +2792,24 @@ out: return; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) || !defined(SCSI_EXEC_REQ_FIFO_DEFINED) +#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && \ + defined(SCSI_EXEC_REQ_FIFO_DEFINED)) /* * Can switch to the next dst_sg element, so, to copy to strictly only * one dst_sg element, it must be either last in the chain, or * copy_len == dst_sg->length. */ -static int __sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len, - size_t *pdst_offs, struct scatterlist *src_sg, - size_t copy_len, - enum km_type d_km_type, enum km_type s_km_type) +static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len, + size_t *pdst_offs, struct scatterlist *src_sg, + size_t copy_len, + enum km_type d_km_type, enum km_type s_km_type) { int res = 0; struct scatterlist *dst_sg; size_t src_len, dst_len, src_offs, dst_offs; struct page *src_page, *dst_page; - if (copy_len == 0) - copy_len = 0x7FFFFFFF; /* copy all */ - dst_sg = *pdst_sg; dst_len = *pdst_len; dst_offs = *pdst_offs; @@ -2865,35 +2874,11 @@ out: return res; } -/** - * sg_copy_elem - copy one SG element to another - * @dst_sg: destination SG element - * @src_sg: source SG element - * @copy_len: maximum amount of data to copy. If 0, then copy all. - * @d_km_type: kmap_atomic type for the destination SG - * @s_km_type: kmap_atomic type for the source SG - * - * Description: - * Data from the source SG element will be copied to the destination SG - * element. Returns number of bytes copied. Can switch to the next dst_sg - * element, so, to copy to strictly only one dst_sg element, it must be - * either last in the chain, or copy_len == dst_sg->length. - */ -int sg_copy_elem(struct scatterlist *dst_sg, struct scatterlist *src_sg, - size_t copy_len, enum km_type d_km_type, - enum km_type s_km_type) -{ - size_t dst_len = dst_sg->length, dst_offs = dst_sg->offset; - - return __sg_copy_elem(&dst_sg, &dst_len, &dst_offs, src_sg, - copy_len, d_km_type, s_km_type); -} - - /** * sg_copy - copy one SG vector to another * @dst_sg: destination SG * @src_sg: source SG + * @nents_to_copy: maximum number of entries to copy * @copy_len: maximum amount of data to copy. If 0, then copy all. * @d_km_type: kmap_atomic type for the destination SG * @s_km_type: kmap_atomic type for the source SG @@ -2903,8 +2888,8 @@ int sg_copy_elem(struct scatterlist *dst_sg, struct scatterlist *src_sg, * vector. End of the vectors will be determined by sg_next() returning * NULL. Returns number of bytes copied. */ -int sg_copy(struct scatterlist *dst_sg, - struct scatterlist *src_sg, size_t copy_len, +int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, + int nents_to_copy, size_t copy_len, enum km_type d_km_type, enum km_type s_km_type) { int res = 0; @@ -2913,185 +2898,143 @@ int sg_copy(struct scatterlist *dst_sg, if (copy_len == 0) copy_len = 0x7FFFFFFF; /* copy all */ + if (nents_to_copy == 0) + nents_to_copy = 0x7FFFFFFF; /* copy all */ + dst_len = dst_sg->length; dst_offs = dst_sg->offset; do { - copy_len -= __sg_copy_elem(&dst_sg, &dst_len, &dst_offs, + int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs, src_sg, copy_len, d_km_type, s_km_type); + copy_len -= copied; + res += copied; if ((copy_len == 0) || (dst_sg == NULL)) goto out; + nents_to_copy--; + if (nents_to_copy == 0) + goto out; + src_sg = sg_next(src_sg); } while (src_sg != NULL); out: return res; } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) || !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && !defined(SCSI_EXEC_REQ_FIFO_DEFINED) +#endif /* !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && \ + defined(SCSI_EXEC_REQ_FIFO_DEFINED)) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) && \ + !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && \ + defined(SCSI_EXEC_REQ_FIFO_DEFINED)) + #include -struct blk_kern_sg_hdr { - struct scatterlist *orig_sgp; - union { - struct sg_table new_sg_table; - struct scatterlist *saved_sg; - }; - bool tail_only; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +static inline int object_is_on_stack(void *obj) +{ + void *stack = task_stack_page(current); + + return (obj >= stack) && (obj < (stack + THREAD_SIZE)); +} +#endif + +struct blk_kern_sg_work { + atomic_t bios_inflight; + struct sg_table sg_table; + struct scatterlist *src_sgl; }; -#define BLK_KERN_SG_HDR_ENTRIES (1 + (sizeof(struct blk_kern_sg_hdr) - 1) / \ - sizeof(struct scatterlist)) +static void blk_rq_unmap_kern_sg(struct request *rq, int err); -/** - * blk_rq_unmap_kern_sg - "unmaps" data buffers in the request - * @req: request to unmap - * @do_copy: sets copy data between buffers, if needed, or not - * - * Description: - * It frees all additional buffers allocated for SG->BIO mapping. - */ -void blk_rq_unmap_kern_sg(struct request *req, int do_copy) +static void blk_free_kern_sg_work(struct blk_kern_sg_work *bw) { - struct blk_kern_sg_hdr *hdr = (struct blk_kern_sg_hdr *)req->end_io_data; - - if (hdr == NULL) - goto out; - - if (hdr->tail_only) { - /* Tail element only was copied */ - struct scatterlist *saved_sg = hdr->saved_sg; - struct scatterlist *tail_sg = hdr->orig_sgp; - - if ((rq_data_dir(req) == READ) && do_copy) - sg_copy_elem(saved_sg, tail_sg, tail_sg->length, - KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ); - - __free_pages(sg_page(tail_sg), get_order(tail_sg->length)); - *tail_sg = *saved_sg; - kfree(hdr); - } else { - /* The whole SG was copied */ - struct sg_table new_sg_table = hdr->new_sg_table; - struct scatterlist *new_sgl = new_sg_table.sgl + - BLK_KERN_SG_HDR_ENTRIES; - struct scatterlist *orig_sgl = hdr->orig_sgp; - - if ((rq_data_dir(req) == READ) && do_copy) - sg_copy(orig_sgl, new_sgl, 0, KM_BIO_DST_IRQ, - KM_BIO_SRC_IRQ); - - sg_free_table(&new_sg_table); - } - -out: + TRACE_DBG("Freeing bw %p", bw); + sg_free_table(&bw->sg_table); + kfree(bw); return; } -static int blk_rq_handle_align_tail_only(struct request *rq, - struct scatterlist *sg_to_copy, - gfp_t gfp, gfp_t page_gfp) +static void blk_bio_map_kern_endio(struct bio *bio, int err) { - int res = 0; - struct scatterlist *tail_sg = sg_to_copy; - struct scatterlist *saved_sg; - struct blk_kern_sg_hdr *hdr; - int saved_sg_nents; - struct page *pg; + struct blk_kern_sg_work *bw = bio->bi_private; - saved_sg_nents = 1 + BLK_KERN_SG_HDR_ENTRIES; + TRACE_DBG("bio %p finished", bio); - saved_sg = kmalloc(sizeof(*saved_sg) * saved_sg_nents, gfp); - if (saved_sg == NULL) - goto out_nomem; + if (bw != NULL) { + /* Decrement the bios in processing and, if zero, free */ + BUG_ON(atomic_read(&bw->bios_inflight) <= 0); + if (atomic_dec_and_test(&bw->bios_inflight)) { + TRACE_DBG("sgl %p, new_sgl %p, new_sgl_nents %d", + bw->src_sgl, bw->sg_table.sgl, + bw->sg_table.nents); + if ((bio_data_dir(bio) == READ) && (err == 0)) { + unsigned long flags; - sg_init_table(saved_sg, saved_sg_nents); + TRACE_DBG("Copying sgl %p (nents %d) to " + "orig_sgl %p", bw->sg_table.sgl, + bw->sg_table.nents, bw->src_sgl); - hdr = (struct blk_kern_sg_hdr *)saved_sg; - saved_sg += BLK_KERN_SG_HDR_ENTRIES; - saved_sg_nents -= BLK_KERN_SG_HDR_ENTRIES; + local_irq_save(flags); /* to protect KMs */ + sg_copy(bw->src_sgl, bw->sg_table.sgl, 0, 0, + KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ); + local_irq_restore(flags); + } + blk_free_kern_sg_work(bw); + } + } - hdr->tail_only = true; - hdr->orig_sgp = tail_sg; - hdr->saved_sg = saved_sg; - - *saved_sg = *tail_sg; - - pg = alloc_pages(page_gfp, get_order(tail_sg->length)); - if (pg == NULL) - goto err_free_saved_sg; - - sg_assign_page(tail_sg, pg); - tail_sg->offset = 0; - - if (rq_data_dir(rq) == WRITE) - sg_copy_elem(tail_sg, saved_sg, saved_sg->length, - KM_USER1, KM_USER0); - - rq->end_io_data = hdr; - rq->cmd_flags |= REQ_COPY_USER; - -out: - return res; - -err_free_saved_sg: - kfree(saved_sg); - -out_nomem: - res = -ENOMEM; - goto out; + bio_put(bio); + return; } -static int blk_rq_handle_align(struct request *rq, struct scatterlist **psgl, - int *pnents, struct scatterlist *sgl_to_copy, - int nents_to_copy, gfp_t gfp, gfp_t page_gfp) +static int blk_rq_copy_kern_sg(struct request *rq, struct scatterlist *sgl, + int nents, struct blk_kern_sg_work **pbw, + gfp_t gfp, gfp_t page_gfp) { int res = 0, i; - struct scatterlist *sgl = *psgl; - int nents = *pnents; - struct sg_table sg_table; struct scatterlist *sg; struct scatterlist *new_sgl; - size_t len = 0, to_copy; int new_sgl_nents; - struct blk_kern_sg_hdr *hdr; + size_t len = 0, to_copy; + struct blk_kern_sg_work *bw; - if (sgl != sgl_to_copy) { - /* copy only the last element */ - res = blk_rq_handle_align_tail_only(rq, sgl_to_copy, - gfp, page_gfp); - if (res == 0) - goto out; - /* else go through */ + bw = kzalloc(sizeof(*bw), gfp); + if (bw == NULL) { + PRINT_ERROR("%s", "Unable to alloc blk_kern_sg_work"); + goto out; } + bw->src_sgl = sgl; + for_each_sg(sgl, sg, nents, i) len += sg->length; to_copy = len; - new_sgl_nents = PFN_UP(len) + BLK_KERN_SG_HDR_ENTRIES; + new_sgl_nents = PFN_UP(len); - res = sg_alloc_table(&sg_table, new_sgl_nents, gfp); - if (res != 0) - goto out; + res = sg_alloc_table(&bw->sg_table, new_sgl_nents, gfp); + if (res != 0) { + PRINT_ERROR("Unable to alloc copy sg table (nents %d)", + new_sgl_nents); + goto out_free_bw; + } - new_sgl = sg_table.sgl; - hdr = (struct blk_kern_sg_hdr *)new_sgl; - new_sgl += BLK_KERN_SG_HDR_ENTRIES; - new_sgl_nents -= BLK_KERN_SG_HDR_ENTRIES; + new_sgl = bw->sg_table.sgl; - hdr->tail_only = false; - hdr->orig_sgp = sgl; - hdr->new_sg_table = sg_table; + TRACE_DBG("sgl %p, nents %d, to_copy %d, new_sgl %p, new_sgl_nents %d", + sgl, nents, to_copy, new_sgl, new_sgl_nents); for_each_sg(new_sgl, sg, new_sgl_nents, i) { struct page *pg; pg = alloc_page(page_gfp); - if (pg == NULL) + if (pg == NULL) { + PRINT_ERROR("Unable to alloc copy page (left %d)", len); goto err_free_new_sgl; + } sg_assign_page(sg, pg); sg->length = min_t(size_t, PAGE_SIZE, len); @@ -3102,18 +3045,23 @@ static int blk_rq_handle_align(struct request *rq, struct scatterlist **psgl, if (rq_data_dir(rq) == WRITE) { /* * We need to limit amount of copied data to to_copy, because - * sgl might have the last element not marked as last in + * sgl might have the last element in sgl not marked as last in * SG chaining. */ - sg_copy(new_sgl, sgl, to_copy, KM_USER0, KM_USER1); + TRACE_DBG("Copying sgl %p (nents %d) to new_sgl %p " + "(new_sgl_nents %d), to_copy %d", sgl, nents, + new_sgl, new_sgl_nents, to_copy); + sg_copy(new_sgl, sgl, 0, to_copy, + KM_USER0, KM_USER1); } - rq->end_io_data = hdr; + *pbw = bw; + /* + * REQ_COPY_USER name is misleading. It should be something like + * REQ_HAS_TAIL_SPACE_FOR_PADDING. + */ rq->cmd_flags |= REQ_COPY_USER; - *psgl = new_sgl; - *pnents = new_sgl_nents; - out: return res; @@ -3124,20 +3072,16 @@ err_free_new_sgl: break; __free_page(pg); } - sg_free_table(&sg_table); + sg_free_table(&bw->sg_table); +out_free_bw: + kfree(bw); res = -ENOMEM; goto out; } -static void bio_map_kern_endio(struct bio *bio, int err) -{ - bio_put(bio); -} - static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, - int nents, gfp_t gfp, struct scatterlist **sgl_to_copy, - int *nents_to_copy) + int nents, struct blk_kern_sg_work *bw, gfp_t gfp) { int res; struct request_queue *q = rq->q; @@ -3147,10 +3091,9 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, bool need_new_bio; struct scatterlist *sg, *prev_sg = NULL; struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + int bios; - *sgl_to_copy = NULL; - - if (unlikely((sgl == 0) || (nents <= 0))) { + if (unlikely((sgl == NULL) || (sgl->length == 0) || (nents <= 0))) { WARN_ON(1); res = -EINVAL; goto out; @@ -3164,8 +3107,12 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, ((PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec)), BIO_MAX_PAGES); + TRACE_DBG("sgl %p, nents %d, bw %p, max_nr_vecs %d", sgl, nents, bw, + max_nr_vecs); + need_new_bio = true; tot_len = 0; + bios = 0; for_each_sg(sgl, sg, nents, i) { struct page *page = sg_page(sg); void *page_addr = page_address(page); @@ -3187,8 +3134,9 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, l = len; if (((sg->offset | l) & queue_dma_alignment(q)) || (page_addr && object_is_on_stack(page_addr + sg->offset))) { + TRACE_DBG("%s", "DMA alignment or offset don't match"); res = -EINVAL; - goto out_need_copy; + goto out_free_bios; } while (len > 0) { @@ -3196,16 +3144,25 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, int rc; if (need_new_bio) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) bio = bio_kmalloc(gfp, max_nr_vecs); +#else + bio = bio_alloc(gfp, max_nr_vecs); +#endif if (bio == NULL) { + PRINT_ERROR("%s", "Can't to alloc bio"); res = -ENOMEM; goto out_free_bios; } + TRACE_DBG("bio %p alloced", bio); + if (rw == WRITE) bio->bi_rw |= 1 << BIO_RW; - bio->bi_end_io = bio_map_kern_endio; + bios++; + bio->bi_private = bw; + bio->bi_end_io = blk_bio_map_kern_endio; if (hbio == NULL) hbio = tbio = bio; @@ -3222,7 +3179,9 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, res = rc; else res = -EIO; - goto out_need_copy; + PRINT_ERROR("bio_add_pc_page() failed: " + "%d", rc); + goto out_free_bios; } else { need_new_bio = true; len -= rc; @@ -3246,15 +3205,15 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, /* Total length must be aligned on DMA padding alignment */ if ((tot_len & q->dma_pad_mask) && !(rq->cmd_flags & REQ_COPY_USER)) { + TRACE_DBG("Total len %d doesn't match DMA pad mask %x", + tot_len, q->dma_pad_mask); res = -EINVAL; - if (sgl->offset == 0) { - *sgl_to_copy = prev_sg; - *nents_to_copy = 1; - goto out_free_bios; - } else - goto out_need_copy; + goto out_free_bios; } + if (bw != NULL) + atomic_set(&bw->bios_inflight, bios); + while (hbio != NULL) { bio = hbio; hbio = hbio->bi_next; @@ -3264,21 +3223,18 @@ static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, res = blk_rq_append_bio(q, rq, bio); if (unlikely(res != 0)) { + PRINT_ERROR("blk_rq_append_bio() failed: %d", res); bio->bi_next = hbio; hbio = bio; - goto out_free_bios; + /* We can have one or more bios bounced */ + goto out_unmap_bios; } } rq->buffer = rq->data = NULL; - out: return res; -out_need_copy: - *sgl_to_copy = sgl; - *nents_to_copy = nents; - out_free_bios: while (hbio != NULL) { bio = hbio; @@ -3286,6 +3242,10 @@ out_free_bios: bio_put(bio); } goto out; + +out_unmap_bios: + blk_rq_unmap_kern_sg(rq, res); + goto out; } /** @@ -3299,35 +3259,28 @@ out_free_bios: * Data will be mapped directly if possible. Otherwise a bounce * buffer will be used. */ -int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, +static int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, int nents, gfp_t gfp) { int res; - struct scatterlist *sg_to_copy = NULL; - int nents_to_copy = 0; - if (unlikely((sgl == 0) || (sgl->length == 0) || - (nents <= 0) || (rq->end_io_data != NULL))) { - WARN_ON(1); - res = -EINVAL; - goto out; - } - - res = __blk_rq_map_kern_sg(rq, sgl, nents, gfp, &sg_to_copy, - &nents_to_copy); + res = __blk_rq_map_kern_sg(rq, sgl, nents, NULL, gfp); if (unlikely(res != 0)) { - if (sg_to_copy == NULL) - goto out; + struct blk_kern_sg_work *bw = NULL; - res = blk_rq_handle_align(rq, &sgl, &nents, sg_to_copy, - nents_to_copy, gfp, rq->q->bounce_gfp | gfp); + TRACE_DBG("__blk_rq_map_kern_sg() failed: %d", res); + + res = blk_rq_copy_kern_sg(rq, sgl, nents, &bw, + gfp, rq->q->bounce_gfp | gfp); if (unlikely(res != 0)) goto out; - res = __blk_rq_map_kern_sg(rq, sgl, nents, gfp, &sg_to_copy, - &nents_to_copy); + res = __blk_rq_map_kern_sg(rq, bw->sg_table.sgl, + bw->sg_table.nents, bw, gfp); if (res != 0) { - blk_rq_unmap_kern_sg(rq, 0); + TRACE_DBG("Copied __blk_rq_map_kern_sg() failed: %d", + res); + blk_free_kern_sg_work(bw); goto out; } } @@ -3338,97 +3291,175 @@ out: return res; } -struct scsi_io_context { - void *blk_data; - void *data; - void (*done)(void *data, char *sense, int result, int resid); - char sense[SCSI_SENSE_BUFFERSIZE]; -}; +/** + * blk_rq_unmap_kern_sg - unmap a request with kernel sg + * @rq: request to unmap + * @err: non-zero error code + * + * Description: + * Unmap a rq previously mapped by blk_rq_map_kern_sg(). Must be called + * only in case of an error! + */ +static void blk_rq_unmap_kern_sg(struct request *rq, int err) +{ + struct bio *bio = rq->bio; + + while (bio) { + struct bio *b = bio; + bio = bio->bi_next; + b->bi_end_io(b, err); + } + rq->bio = 0; + + return; +} + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) && \ + !(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && \ + defined(SCSI_EXEC_REQ_FIFO_DEFINED)) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) static void scsi_end_async(struct request *req, int error) { struct scsi_io_context *sioc = req->end_io_data; - req->end_io_data = sioc->blk_data; - blk_rq_unmap_kern_sg(req, (error == 0)); + TRACE_DBG("sioc %p, cmd %p", sioc, sioc->data); if (sioc->done) sioc->done(sioc->data, sioc->sense, req->errors, req->data_len); - kfree(sioc); + if (!sioc->full_cdb_used) + kmem_cache_free(scsi_io_context_cache, sioc); + else + kfree(sioc); + __blk_put_request(req->q, req); + return; } /** - * scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb - * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE - * @sgl: data buffer scatterlist - * @nents: number of elements in the sgl - * @timeout: request timeout in seconds - * @retries: number of times to retry request - * @privdata: data passed to done() + * scst_scsi_exec_async - executes a SCSI command in pass-through mode + * @cmd: scst command * @done: callback function when done - * @gfp: memory allocation flags - * @flags: one or more SCSI_ASYNC_EXEC_FLAG_* flags */ -int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, - int cmd_len, int data_direction, struct scatterlist *sgl, - int nents, int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), gfp_t gfp, - int flags) +int scst_scsi_exec_async(struct scst_cmd *cmd, + void (*done)(void *, char *, int, int)) { - struct request *req; + int res = 0; + struct request_queue *q = cmd->dev->scsi_dev->request_queue; + struct request *rq; struct scsi_io_context *sioc; - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); + int write = (cmd->data_direction & SCST_DATA_WRITE) ? WRITE : READ; + gfp_t gfp = scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL; + int cmd_len = cmd->cdb_len; - sioc = kzalloc(sizeof(*sioc), gfp); - if (sioc == NULL) - return DRIVER_ERROR << 24; + if (cmd->ext_cdb_len == 0) { + TRACE_DBG("Simple CDB (cmd_len %d)", cmd_len); + sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp); + if (sioc == NULL) { + res = -ENOMEM; + goto out; + } + } else { + cmd_len += cmd->ext_cdb_len; - req = blk_get_request(sdev->request_queue, write, gfp); - if (req == NULL) - goto free_sense; - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; + TRACE_DBG("Extended CDB (cmd_len %d)", cmd_len); - if (flags & SCSI_ASYNC_EXEC_FLAG_HAS_TAIL_SPACE_FOR_PADDING) - req->cmd_flags |= REQ_COPY_USER; + sioc = kzalloc(sizeof(*sioc) + cmd_len, gfp); + if (sioc == NULL) { + res = -ENOMEM; + goto out; + } - if (sgl != NULL) { - err = blk_rq_map_kern_sg(req, sgl, nents, gfp); - if (err) - goto free_req; + sioc->full_cdb_used = 1; + + memcpy(sioc->full_cdb, cmd->cdb, cmd->cdb_len); + memcpy(&sioc->full_cdb[cmd->cdb_len], cmd->ext_cdb, + cmd->ext_cdb_len); } - sioc->blk_data = req->end_io_data; - sioc->data = privdata; + rq = blk_get_request(q, write, gfp); + if (rq == NULL) { + res = -ENOMEM; + goto out_free_sioc; + } + + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_flags |= REQ_QUIET; + + if (cmd->sg != NULL) { + res = blk_rq_map_kern_sg(rq, cmd->sg, cmd->sg_cnt, gfp); + if (res) { + TRACE_DBG("blk_rq_map_kern_sg() failed: %d", res); + goto out_free_rq; + } + } + + if (cmd->data_direction == SCST_DATA_BIDI) { + struct request *next_rq; + + if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) { + res = -EOPNOTSUPP; + goto out_free_unmap; + } + + next_rq = blk_get_request(q, READ, gfp); + if (next_rq == NULL) { + res = -ENOMEM; + goto out_free_unmap; + } + rq->next_rq = next_rq; + next_rq->cmd_type = rq->cmd_type; + + res = blk_rq_map_kern_sg(next_rq, cmd->in_sg, + cmd->in_sg_cnt, gfp); + if (res != 0) + goto out_free_unmap; + } + + TRACE_DBG("sioc %p, cmd %p", sioc, cmd); + + sioc->data = cmd; sioc->done = done; - req->cmd_len = cmd_len; - memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = sioc->sense; - req->sense_len = 0; - req->timeout = timeout; - req->retries = retries; - req->end_io_data = sioc; + rq->cmd_len = cmd_len; + if (cmd->ext_cdb_len == 0) { + memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ + memcpy(rq->cmd, cmd->cdb, cmd->cdb_len); + } else + rq->cmd = sioc->full_cdb; - blk_execute_rq_nowait(req->q, NULL, req, - flags & SCSI_ASYNC_EXEC_FLAG_AT_HEAD, scsi_end_async); - return 0; + rq->sense = sioc->sense; + rq->sense_len = sizeof(sioc->sense); + rq->timeout = cmd->timeout; + rq->retries = cmd->retries; + rq->end_io_data = sioc; -free_req: - blk_put_request(req); + blk_execute_rq_nowait(rq->q, NULL, rq, + (cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE), scsi_end_async); +out: + return res; -free_sense: - kfree(sioc); - return DRIVER_ERROR << 24; +out_free_unmap: + if (rq->next_rq != NULL) { + blk_put_request(rq->next_rq); + rq->next_rq = 0; + } + blk_rq_unmap_kern_sg(rq, res); + +out_free_rq: + blk_put_request(rq); + +out_free_sioc: + if (!sioc->full_cdb_used) + kmem_cache_free(scsi_io_context_cache, sioc); + else + kfree(sioc); + goto out; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */ + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) */ void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir) { @@ -3466,8 +3497,9 @@ void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir) goto out; } - sg_copy(dst_sg, src_sg, to_copy, atomic ? KM_SOFTIRQ0 : KM_USER0, - atomic ? KM_SOFTIRQ1 : KM_USER1); + sg_copy(dst_sg, src_sg, 0, to_copy, + atomic ? KM_SOFTIRQ0 : KM_USER0, + atomic ? KM_SOFTIRQ1 : KM_USER1); out: TRACE_EXIT(); @@ -5261,7 +5293,7 @@ out: return; } -void __init scst_scsi_op_list_init(void) +static void __init scst_scsi_op_list_init(void) { int i; uint8_t op = 0xff; @@ -5282,6 +5314,38 @@ void __init scst_scsi_op_list_init(void) return; } +int __init scst_lib_init(void) +{ + int res = 0; + + scst_scsi_op_list_init(); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + scsi_io_context_cache = kmem_cache_create("scst_scsi_io_context", + sizeof(struct scsi_io_context), + 0, 0, NULL); + if (!scsi_io_context_cache) { + PRINT_ERROR("%s", "Can't init scsi io context cache"); + res = -ENOMEM; + goto out; + } + +out: +#endif + TRACE_EXIT_RES(res); + return res; +} + +void scst_lib_exit(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + BUILD_BUG_ON(SCST_MAX_CDB_SIZE != BLK_MAX_CDB); + BUILD_BUG_ON(SCST_SENSE_BUFFERSIZE < SCSI_SENSE_BUFFERSIZE); + + kmem_cache_destroy(scsi_io_context_cache); +#endif +} + #ifdef CONFIG_SCST_DEBUG /* Original taken from the XFS code */ unsigned long scst_random(void) diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 71781c81b..4a56cb8a4 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -40,7 +40,7 @@ details." #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) #if !defined(SCSI_EXEC_REQ_FIFO_DEFINED) && \ !defined(CONFIG_SCST_STRICT_SERIALIZING) #warning "Patch scst_exec_req_fifo- was not applied on\ @@ -915,7 +915,7 @@ int __scst_register_dev_driver(struct scst_dev_type *dev_type, if (res != 0) goto out_error; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) #if !defined(SCSI_EXEC_REQ_FIFO_DEFINED) && \ !defined(CONFIG_SCST_STRICT_SERIALIZING) if (dev_type->exec == NULL) { @@ -1670,7 +1670,7 @@ static void __init scst_print_config(void) static int __init init_scst(void) { - int res = 0, i; + int res, i; int scst_num_cpus; TRACE_ENTRY(); @@ -1737,6 +1737,10 @@ static int __init init_scst(void) list_add_tail(&scst_main_cmd_lists.lists_list_entry, &scst_cmd_lists_list); + res = scst_lib_init(); + if (res != 0) + goto out; + scst_num_cpus = num_online_cpus(); /* ToDo: register_cpu_notifier() */ @@ -1761,7 +1765,7 @@ static int __init init_scst(void) } \ } while (0) - INIT_CACHEP(scst_mgmt_cachep, scst_mgmt_cmd, out); + INIT_CACHEP(scst_mgmt_cachep, scst_mgmt_cmd, out_lib_exit); INIT_CACHEP(scst_mgmt_stub_cachep, scst_mgmt_cmd_stub, out_destroy_mgmt_cache); INIT_CACHEP(scst_ua_cachep, scst_tgt_dev_UA, @@ -1856,8 +1860,6 @@ static int __init init_scst(void) if (res != 0) goto out_free_acg; - scst_scsi_op_list_init(); - for (i = 0; i < (int)ARRAY_SIZE(scst_tasklets); i++) { spin_lock_init(&scst_tasklets[i].tasklet_lock); INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list); @@ -1940,6 +1942,9 @@ out_destroy_mgmt_stub_cache: out_destroy_mgmt_cache: kmem_cache_destroy(scst_mgmt_cachep); + +out_lib_exit: + scst_lib_exit(); goto out; } @@ -1979,6 +1984,8 @@ static void __exit exit_scst(void) DEINIT_CACHEP(scst_tgtd_cachep); DEINIT_CACHEP(scst_acgd_cachep); + scst_lib_exit(); + PRINT_INFO("%s", "SCST unloaded"); TRACE_EXIT(); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index f8b2a4a26..468ecce97 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -349,7 +349,7 @@ static inline void scst_do_req(struct scsi_request *sreq, scsi_do_req_fifo(sreq, cmnd, buffer, bufflen, done, timeout, retries); #endif } -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) static inline int scst_exec_req(struct scsi_device *sdev, const unsigned char *cmd, int cmd_len, int data_direction, struct scatterlist *sgl, unsigned bufflen, unsigned nents, @@ -367,20 +367,15 @@ static inline int scst_exec_req(struct scsi_device *sdev, (void *)sgl, bufflen, nents, timeout, retries, privdata, done, gfp); #endif } -#else /* i.e. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ -#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED) -#define SCSI_ASYNC_EXEC_FLAG_AT_HEAD 1 -#define SCSI_ASYNC_EXEC_FLAG_HAS_TAIL_SPACE_FOR_PADDING 2 -int scsi_execute_async(struct scsi_device *sdev, - const unsigned char *cmd, int cmd_len, int data_direction, - struct scatterlist *sgl, int nents, int timeout, int retries, - void *privdata, void (*done)(void *, char *, int, int), - gfp_t gfp, int flags); -#endif +#else /* i.e. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) */ +int scst_scsi_exec_async(struct scst_cmd *cmd, + void (*done)(void *, char *, int, int)); #endif int scst_alloc_space(struct scst_cmd *cmd); -void scst_scsi_op_list_init(void); + +int scst_lib_init(void); +void scst_lib_exit(void); enum scst_sg_copy_dir { SCST_SG_COPY_FROM_TARGET, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 7e1a792bc..8237eade3 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -2039,25 +2039,20 @@ static int scst_do_real_exec(struct scst_cmd *cmd) cmd->scsi_req->sr_bufflen, scst_cmd_done, cmd->timeout, cmd->retries); #else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) rc = scst_exec_req(dev->scsi_dev, cmd->cdb, cmd->cdb_len, cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, cmd->timeout, cmd->retries, cmd, scst_cmd_done, atomic ? GFP_ATOMIC : GFP_KERNEL); #else - rc = scsi_execute_async(dev->scsi_dev, cmd->cdb, cmd->cdb_len, - cmd->data_direction, cmd->sg, cmd->sg_cnt, - cmd->timeout, cmd->retries, cmd, scst_cmd_done, - atomic ? GFP_ATOMIC : GFP_KERNEL, - cmd->tgt_data_buf_alloced ? 0 : - SCSI_ASYNC_EXEC_FLAG_HAS_TAIL_SPACE_FOR_PADDING); + rc = scst_scsi_exec_async(cmd, scst_cmd_done); #endif if (unlikely(rc != 0)) { if (atomic) { res = SCST_EXEC_NEED_THREAD; goto out_restore; } else { - PRINT_ERROR("scst_exec_req() failed: %x", rc); + PRINT_ERROR("scst pass-through exec failed: %x", rc); goto out_error; } }