1. Added support of 2.6.18 kernels
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 26 Oct 2006 16:08:29 +0000 (16:08 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 26 Oct 2006 16:08:29 +0000 (16:08 +0000)
2. FILEIO_ONLY added

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@14 d57e44dd-8a1f-0410-8b47-8ef2f437770f

scst/ChangeLog
scst/README
scst/include/scsi_tgt.h
scst/kernel/26_scst-2.6.18.patch [new file with mode: 0644]
scst/src/Makefile
scst/src/scst.c
scst/src/scst_lib.c
scst/src/scst_priv.h
scst/src/scst_targ.c

index a54f374..f16bb38 100644 (file)
@@ -4,6 +4,12 @@ Summary of changes between versions 0.9.4 and 0.9.5
  - Fixed many found task management related problems, especially in the
    RESETs area. DEBUG_TM compilation option added (see README).
 
+ - Updated to work on kernels version 2.6.18+.
+
+ - FILEIO_ONLY added. If it's defined, there is no need to patch the
+   kernel, but pass-through modules (scst_disk, scst_tape, etc.) are not
+   supported).
+
  - Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status
    implemented.
 
index 7db2b42..fcc9d38 100644 (file)
@@ -134,6 +134,11 @@ Compilation options
 There are the following compilation options, that could be commented
 in/out in Makefile:
 
+ - FILEIO_ONLY - if defined, the pass-through device handlers
+   (scst_disk, scst_tape) will not work, but SCST will not require the
+   kernel patching. Defined by default to ease new people try SCST on
+   their kernels.
+
  - DEBUG - turns on some debugging code, including some logging. Makes
    the driver considerably bigger and slower, producing large amount of
    log data.
@@ -424,12 +429,18 @@ IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
 
 IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
 =========  you can't get good write performance for FILEIO devices with
-           default 512 bytes block sizes. You could get about 10% of
-          the expected one. This is because of "unusual" write access
+           default 512 bytes block sizes. You could get about 10% of the
+          expected one. This is because of "unusual" write access
           pattern, with which Windows'es write data and which is
-          (simplifying) incompatible with how Linux page cache works.
+          (simplifying) incompatible with how Linux page cache works,
+          so for each write the corresponding block must be read first.
           With 4096 bytes block sizes for FILEIO devices the write
-          performance will be as expected.
+          performance will be as expected. Actually, any system on
+          initiator, not only Windows, will benefit from block size
+          max(PAGE_SIZE, BLOCK_SIZE_ON_UNDERLYING_FS), where PAGE_SIZE
+          is the page size, BLOCK_SIZE_ON_UNDERLYING_FS is block size on
+          the underlying FS, on which the device file located, or 0, if
+          a device node is used. Both values are on the target.
 
 Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x
 kernel, where we did carefull performance study, aggregate throuhput
index 0068492..0954535 100644 (file)
@@ -1026,7 +1026,9 @@ struct scst_cmd
 
        struct scst_tgt_dev *tgt_dev;   /* corresponding device for this cmd */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
        struct scsi_request *scsi_req;  /* SCSI request */
+#endif
 
        /* List entry for tgt_dev's SN related lists */
        struct list_head sn_cmd_list_entry;
diff --git a/scst/kernel/26_scst-2.6.18.patch b/scst/kernel/26_scst-2.6.18.patch
new file mode 100644 (file)
index 0000000..a1eb646
--- /dev/null
@@ -0,0 +1,106 @@
+--- linux-2.6.18.1-scst-dbg/drivers/scsi/scsi_lib.c_scst       2006-09-20 07:42:06.000000000 +0400
++++ linux-2.6.18.1-scst-dbg/drivers/scsi/scsi_lib.c    2006-10-25 20:52:58.000000000 +0400
+@@ -367,7 +367,7 @@
+ }
+ /**
+- * scsi_execute_async - insert request
++ * __scsi_execute_async - insert request
+  * @sdev:     scsi device
+  * @cmd:      scsi command
+  * @cmd_len:  length of scsi cdb
+@@ -378,11 +378,14 @@
+  * @timeout:  request timeout in seconds
+  * @retries:  number of times to retry request
+  * @flags:    or into request 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;
+@@ -418,7 +421,7 @@
+       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:
+@@ -427,8 +430,53 @@
+       kfree(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_fifi - 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()
+  *
+--- linux-2.6.18.1-scst-dbg/include/scsi/scsi_device.h_scst    2006-09-20 07:42:06.000000000 +0400
++++ linux-2.6.18.1-scst-dbg/include/scsi/scsi_device.h 2006-10-25 20:09:23.000000000 +0400
+@@ -297,6 +297,12 @@
+                             int timeout, int retries, void *privdata,
+                             void (*done)(void *, char *, int, int),
+                             gfp_t gfp);
++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 void scsi_device_reprobe(struct scsi_device *sdev)
+ {
index 843e118..ba77a77 100644 (file)
@@ -75,7 +75,8 @@ EXTRA_CFLAGS += -I$(INC_DIR)
 
 #EXTRA_CFLAGS += -DSTRICT_SERIALIZING
 
-EXTRA_CFLAGS += -DEXTRACHECKS 
+EXTRA_CFLAGS += -DEXTRACHECKS
+#EXTRA_CFLAGS += -DFILEIO_ONLY
 
 #EXTRA_CFLAGS += -fno-inline
 
index 20e8c8e..aa2c277 100644 (file)
@@ -631,6 +631,16 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
                goto out;
        }
 
+#ifdef FILEIO_ONLY
+       if (dev_type->exec == NULL) {
+               PRINT_ERROR_PR("Pass-through dev handlers (handler %s) not "
+                       "supported. Recompile SCST with undefined FILEIO_ONLY",
+                       dev_type->name);
+               res = -EINVAL;
+               goto out;
+       }
+#endif
+
        if (down_interruptible(&scst_mutex) != 0) {
                res = -EINTR;
                goto out;
@@ -950,11 +960,22 @@ static int __init init_scst(void)
 {
        int res = 0, i;
        struct scst_cmd *cmd;
-       struct scsi_request *req;
 
        TRACE_ENTRY();
 
-       BUILD_BUG_ON(sizeof(cmd->sense_buffer) != sizeof(req->sr_sense_buffer));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       {
+               struct scsi_request *req;
+               BUILD_BUG_ON(sizeof(cmd->sense_buffer) !=
+                       sizeof(req->sr_sense_buffer));
+       }
+#else
+       {
+               struct scsi_sense_hdr *shdr;
+               BUILD_BUG_ON((sizeof(cmd->sense_buffer) < sizeof(*shdr)) &&
+                       (sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE));
+       }
+#endif
 
        scst_num_cpus = get_cpus_count();
        
@@ -1130,6 +1151,9 @@ out_destroy_mgmt_cache:
 
 static void __exit exit_scst(void)
 {
+#ifdef CONFIG_LOCKDEP
+       static /* To hide the lockdep's warning about non-static key */
+#endif
        DECLARE_MUTEX_LOCKED(shm);
 
        TRACE_ENTRY();
index ac952f0..39c4eb9 100644 (file)
@@ -711,6 +711,7 @@ int scst_acg_remove_name(struct scst_acg *acg, const char *name)
        return res;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 static void scst_req_done(struct scsi_cmnd *scsi_cmd)
 {
        struct scsi_request *req;
@@ -776,6 +777,41 @@ out:
        TRACE_EXIT();
        return;
 }
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
+static void scst_send_release(struct scst_tgt_dev *tgt_dev)
+{
+       struct scsi_device *scsi_dev;
+       unsigned char cdb[6];
+       unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+       int rc;
+
+       TRACE_ENTRY();
+       
+       if (tgt_dev->acg_dev->dev->scsi_dev == NULL)
+               goto out;
+
+       scsi_dev = tgt_dev->acg_dev->dev->scsi_dev;
+
+       memset(cdb, 0, sizeof(cdb));
+       cdb[0] = RELEASE;
+       cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
+           ((scsi_dev->lun << 5) & 0xe0) : 0;
+
+       TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI "
+               "mid-level");
+       rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
+                       sense, SCST_DEFAULT_TIMEOUT,
+                       3, GFP_KERNEL);
+       if (rc) {
+               PRINT_INFO_PR("scsi_execute() failed: %d", rc);
+               goto out;
+       }
+
+out:
+       TRACE_EXIT();
+       return;
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
 
 struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
        const char *initiator_name)
@@ -944,7 +980,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
 
        BUG_ON(cmd->blocking);
 
-#ifdef EXTRACHECKS
+#if defined(EXTRACHECKS) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
        if (cmd->scsi_req) {
                PRINT_ERROR_PR("%s: %s", __FUNCTION__, "Cmd with unfreed "
                        "scsi_req!");
@@ -1114,6 +1150,7 @@ void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del)
        return;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 int scst_alloc_request(struct scst_cmd *cmd)
 {
        int res = 0;
@@ -1154,6 +1191,7 @@ void scst_release_request(struct scst_cmd *cmd)
        scsi_release_request(cmd->scsi_req);
        cmd->scsi_req = NULL;
 }
+#endif
 
 int scst_alloc_space(struct scst_cmd *cmd)
 {
index 02b877d..ce02fae 100644 (file)
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_device.h>
-#include <scsi/scsi_request.h>
 #include <scsi/scsi_host.h>
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <scsi/scsi_request.h>
+#endif
+
 #define SCST_MAJOR              177
 
 #define TRACE_RETRY             0x80000000
@@ -250,6 +253,7 @@ static inline void scst_destroy_cmd(struct scst_cmd *cmd)
 void scst_check_retries(struct scst_tgt *tgt, int processible_env);
 void scst_tgt_retry_timer_fn(unsigned long arg);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 int scst_alloc_request(struct scst_cmd *cmd);
 void scst_release_request(struct scst_cmd *cmd);
 
@@ -257,12 +261,33 @@ static inline void scst_do_req(struct scsi_request *sreq,
        const void *cmnd, void *buffer, unsigned bufflen, 
        void (*done)(struct scsi_cmnd *), int timeout, int retries)
 {
-#ifdef STRICT_SERIALIZING
+    #ifdef STRICT_SERIALIZING
        scsi_do_req(sreq, cmnd, buffer, bufflen, done, timeout, retries);
-#else
+    #elif defined(FILEIO_ONLY)
+       BUG();
+    #else
        scsi_do_req_fifo(sreq, cmnd, buffer, bufflen, done, timeout, retries);
-#endif
+    #endif
 }
+#else
+static inline int scst_exec_req(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)
+{
+    #ifdef STRICT_SERIALIZING
+       return scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer,
+               bufflen, use_sg, timeout, retries, privdata, done, gfp);
+    #elif defined(FILEIO_ONLY)
+       BUG();
+       return -1;
+    #else
+       return scsi_execute_async_fifo(sdev, cmd, cmd_len, data_direction,
+               buffer, bufflen, use_sg, timeout, retries, privdata, done, gfp);
+    #endif
+}
+#endif
+
 int scst_alloc_space(struct scst_cmd *cmd);
 void scst_release_space(struct scst_cmd *cmd);
 void scst_scsi_op_list_init(void);
index 3701f50..8eefb9a 100644 (file)
@@ -823,8 +823,8 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
 }
 
 /* No locks supposed to be held */
-static void scst_check_sense(struct scst_cmd *cmd, struct scsi_request *req,
-                            int *next_state)
+static void scst_check_sense(struct scst_cmd *cmd, const uint8_t *rq_sense,
+       int rq_sense_len, int *next_state)
 {
        int sense_valid;
        struct scst_device *dev = cmd->dev;
@@ -848,11 +848,15 @@ static void scst_check_sense(struct scst_cmd *cmd, struct scsi_request *req,
                smp_mb();
        }
 
-       if (req != NULL) {
-               sense_valid = SCST_SENSE_VALID(req->sr_sense_buffer);
+       if (rq_sense != NULL) {
+               sense_valid = SCST_SENSE_VALID(rq_sense);
                if (sense_valid) {
-                       memcpy(cmd->sense_buffer, req->sr_sense_buffer,
-                              sizeof(cmd->sense_buffer));
+                       memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+                       /* 
+                        * We checked that rq_sense_len < sizeof(cmd->sense_buffer)
+                        * in init_scst()
+                        */
+                       memcpy(cmd->sense_buffer, rq_sense, rq_sense_len);
                }
        } else
                sense_valid = SCST_SENSE_VALID(cmd->sense_buffer);
@@ -971,38 +975,60 @@ static int scst_check_auto_sense(struct scst_cmd *cmd)
        return res;
 }
 
-static void scst_do_cmd_done(struct scst_cmd *cmd,
-       struct scsi_request *req, int *next_state)
+static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
+       const uint8_t *rq_sense, int rq_sense_len, int *next_state)
 {
+       unsigned char type;
+
        TRACE_ENTRY();
 
-       cmd->status = req->sr_result & 0xff;
-       cmd->masked_status = status_byte(req->sr_result);
-       cmd->msg_status = msg_byte(req->sr_result);
-       cmd->host_status = host_byte(req->sr_result);
-       cmd->driver_status = driver_byte(req->sr_result);
-       TRACE(TRACE_SCSI, "req->sr_result=%x, cmd->status=%x, "
+       cmd->status = result & 0xff;
+       cmd->masked_status = status_byte(result);
+       cmd->msg_status = msg_byte(result);
+       cmd->host_status = host_byte(result);
+       cmd->driver_status = driver_byte(result);
+       TRACE(TRACE_SCSI, "result=%x, cmd->status=%x, "
              "cmd->masked_status=%x, cmd->msg_status=%x, cmd->host_status=%x, "
-             "cmd->driver_status=%x", req->sr_result, cmd->status,
+             "cmd->driver_status=%x", result, cmd->status,
              cmd->masked_status, cmd->msg_status, cmd->host_status,
              cmd->driver_status);
 
-       scst_check_sense(cmd, req, next_state);
+       cmd->completed = 1;
 
-       cmd->bufflen = req->sr_bufflen; //??
+       scst_dec_on_dev_cmd(cmd);
 
-       /* Clear out request structure */
-       req->sr_use_sg = 0;
-       req->sr_sglist_len = 0;
-       req->sr_bufflen = 0;
-       req->sr_buffer = NULL;
-       req->sr_underflow = 0;
-       req->sr_request->rq_disk = NULL; /* disown request blk */ ;
+       type = cmd->dev->handler->type;
+       if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) &&
+           cmd->tgt_dev->acg_dev->rd_only_flag &&
+           (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD ||
+            type == TYPE_TAPE)) {
+               int32_t length;
+               uint8_t *address;
+
+               length = scst_get_buf_first(cmd, &address);
+               TRACE_DBG("length %d", length);
+               if (unlikely(length <= 0)) {
+                       PRINT_ERROR_PR("%s: scst_get_buf_first() failed",
+                               __func__);
+                       goto next;
+               }
+               if (length > 2 && cmd->cdb[0] == MODE_SENSE) {
+                       address[2] |= 0x80;   /* Write Protect*/
+               }
+               else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) {
+                       address[3] |= 0x80;   /* Write Protect*/
+               }
+               scst_put_buf(cmd, address);
+       }
+
+next:
+       scst_check_sense(cmd, rq_sense, rq_sense_len, next_state);
 
        TRACE_EXIT();
        return;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 static inline struct scst_cmd *scst_get_cmd(struct scsi_cmnd *scsi_cmd,
                                            struct scsi_request **req)
 {
@@ -1025,7 +1051,6 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
        struct scsi_request *req = NULL;
        struct scst_cmd *cmd;
        int next_state;
-       unsigned char type;
 
        TRACE_ENTRY();
 
@@ -1044,37 +1069,57 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
        if (cmd == NULL)
                goto out;
 
-       cmd->completed = 1;
+       next_state = SCST_CMD_STATE_DEV_DONE;
+       scst_do_cmd_done(cmd, req->sr_result, req->sr_sense_buffer,
+               sizeof(req->sr_sense_buffer), &next_state);
 
-       scst_dec_on_dev_cmd(cmd);
+       /* Clear out request structure */
+       req->sr_use_sg = 0;
+       req->sr_sglist_len = 0;
+       req->sr_bufflen = 0;
+       req->sr_buffer = NULL;
+       req->sr_underflow = 0;
+       req->sr_request->rq_disk = NULL; /* disown request blk */
 
-       type = cmd->dev->handler->type;
-       if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) &&
-           cmd->tgt_dev->acg_dev->rd_only_flag &&
-           (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD ||
-            type == TYPE_TAPE)) {
-               int32_t length;
-               uint8_t *address;
+       cmd->bufflen = req->sr_bufflen; //??
 
-               length = scst_get_buf_first(cmd, &address);
-               TRACE_DBG("length %d", length);
-               if (unlikely(length <= 0)) {
-                       goto out;
-               }
-               if (length > 2 && cmd->cdb[0] == MODE_SENSE) {
-                       address[2] |= 0x80;   /* Write Protect*/
-               }
-               else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) {
-                       address[3] |= 0x80;   /* Write Protect*/
-               }
-               scst_put_buf(cmd, address);
-       }
+       scst_release_request(cmd);
 
-       next_state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = next_state;
+       cmd->non_atomic_only = 0;
 
-       scst_do_cmd_done(cmd, req, &next_state);
+       __scst_process_active_cmd(cmd, scst_get_context(), 0);
 
-       scst_release_request(cmd);
+out:
+       TRACE_EXIT();
+       return;
+}
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
+static void scst_cmd_done(void *data, char *sense, int result, int resid)
+{
+       struct scst_cmd *cmd;
+       int next_state;
+
+       TRACE_ENTRY();
+
+       WARN_ON(in_irq());
+
+       /*
+        * We don't use resid, because:
+        * 1. Many low level initiator drivers don't use (set) this field
+        * 2. We determine the command's buffer size directly from CDB,
+        *    so resid is not relevant for us, and target drivers
+        *    should know the residual, if necessary, by comparing expected
+        *    and actual transfer sizes.
+        */
+
+       cmd = (struct scst_cmd *)data;
+       if (cmd == NULL)
+               goto out;
+
+       next_state = SCST_CMD_STATE_DEV_DONE;
+       scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE,
+               &next_state);
 
        cmd->state = next_state;
        cmd->non_atomic_only = 0;
@@ -1085,6 +1130,7 @@ out:
        TRACE_EXIT();
        return;
 }
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
 
 static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
 {
@@ -1133,7 +1179,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
        }
 #endif
 
-       scst_check_sense(cmd, NULL, &next_state);
+       scst_check_sense(cmd, NULL, 0, &next_state);
 
        cmd->state = next_state;
        cmd->non_atomic_only = 0;
@@ -1557,7 +1603,8 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
                        (uint64_t)cmd->lun);
                goto out_error;
        }
-       
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)        
        if (scst_alloc_request(cmd) != 0) {
                PRINT_INFO_PR("%s", "Unable to allocate request, "
                        "sending BUSY status");
@@ -1568,6 +1615,16 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
                    (void *)cmd->scsi_req->sr_buffer,
                    cmd->scsi_req->sr_bufflen, scst_cmd_done, cmd->timeout,
                    cmd->retries);
+#else
+       rc = scst_exec_req(cmd->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,
+                       GFP_KERNEL);
+       if (rc) {
+               PRINT_INFO_PR("scst_exec_req() failed: %d", rc);
+               goto out_error;
+       }
+#endif
 
        rc = SCST_EXEC_COMPLETED;
 
@@ -1593,7 +1650,8 @@ out_error:
        rc = SCST_EXEC_COMPLETED;
        scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
        goto out;
-       
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)        
 out_busy:
        scst_set_busy(cmd);
        cmd->completed = 1;
@@ -1601,6 +1659,7 @@ out_busy:
        rc = SCST_EXEC_COMPLETED;
        scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
        goto out;
+#endif
 
 out_aborted:
        rc = SCST_EXEC_COMPLETED;