1. Added support of 2.6.18 kernels

2. FILEIO_ONLY added


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@14 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2006-10-26 16:08:29 +00:00
parent e19b08fb3b
commit 95a5ad5618
9 changed files with 339 additions and 67 deletions
+6
View 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.
+15 -4
View 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
+2
View 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;
+106
View File
@@ -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)
{
+2 -1
View 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
+26 -2
View 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();
+39 -1
View 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)
{
+29 -4
View File
@@ -24,9 +24,12 @@
#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);
+114 -55
View 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,35 +1069,19 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
if (cmd == NULL)
goto out;
cmd->completed = 1;
scst_dec_on_dev_cmd(cmd);
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)) {
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);
}
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_do_cmd_done(cmd, req, &next_state);
/* 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 */
cmd->bufflen = req->sr_bufflen; //??
scst_release_request(cmd);
@@ -1085,6 +1094,43 @@ 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;
__scst_process_active_cmd(cmd, scst_get_context(), 0);
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;