mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-22 05:01:27 +00:00
CDB splitting added
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2115 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1120,12 +1120,17 @@ struct scst_dev_type {
|
||||
* Pay attention to "atomic" attribute of the cmd, which can be get
|
||||
* by scst_cmd_atomic(): it is true if the function called in the
|
||||
* atomic (non-sleeping) context.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
int (*dev_done) (struct scst_cmd *cmd);
|
||||
|
||||
/*
|
||||
* Called to notify dev hander that the command is about to be freed.
|
||||
*
|
||||
* Could be called on IRQ context.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
void (*on_free_cmd) (struct scst_cmd *cmd);
|
||||
|
||||
@@ -1140,26 +1145,52 @@ struct scst_dev_type {
|
||||
* command should be done
|
||||
*
|
||||
* Called without any locks held from a thread context.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd,
|
||||
struct scst_tgt_dev *tgt_dev);
|
||||
|
||||
/*
|
||||
* Called to notify dev handler that its sg_tablesize is too low to
|
||||
* satisfy this command's data transfer requirements. Should return
|
||||
* true if exec() callback will split this command's CDB on smaller
|
||||
* transfers, false otherwise.
|
||||
*
|
||||
* Could be called on SIRQ context.
|
||||
*
|
||||
* MUST HAVE, if dev handler supports CDB splitting.
|
||||
*/
|
||||
bool (*on_sg_tablesize_low) (struct scst_cmd *cmd);
|
||||
|
||||
/*
|
||||
* Called when new device is attaching to the dev handler
|
||||
* Returns 0 on success, error code otherwise.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
int (*attach) (struct scst_device *dev);
|
||||
|
||||
/* Called when a device is detaching from the dev handler */
|
||||
/*
|
||||
* Called when a device is detaching from the dev handler.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
void (*detach) (struct scst_device *dev);
|
||||
|
||||
/*
|
||||
* Called when new tgt_dev (session) is attaching to the dev handler.
|
||||
* Returns 0 on success, error code otherwise.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
int (*attach_tgt) (struct scst_tgt_dev *tgt_dev);
|
||||
|
||||
/* Called when tgt_dev (session) is detaching from the dev handler */
|
||||
/*
|
||||
* Called when tgt_dev (session) is detaching from the dev handler.
|
||||
*
|
||||
* OPTIONAL
|
||||
*/
|
||||
void (*detach_tgt) (struct scst_tgt_dev *tgt_dev);
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
@@ -3808,4 +3839,10 @@ char *scst_get_next_token_str(char **input_str);
|
||||
void scst_init_threads(struct scst_cmd_threads *cmd_threads);
|
||||
void scst_deinit_threads(struct scst_cmd_threads *cmd_threads);
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid);
|
||||
int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
|
||||
void (*done)(void *data, char *sense, int result, int resid));
|
||||
#endif
|
||||
|
||||
#endif /* __SCST_H */
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define LOG_PREFIX "dev_disk"
|
||||
|
||||
@@ -47,8 +48,12 @@ struct disk_params {
|
||||
static int disk_attach(struct scst_device *dev);
|
||||
static void disk_detach(struct scst_device *dev);
|
||||
static int disk_parse(struct scst_cmd *cmd);
|
||||
static int disk_perf_exec(struct scst_cmd *cmd);
|
||||
static int disk_done(struct scst_cmd *cmd);
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
static int disk_exec(struct scst_cmd *cmd);
|
||||
static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd);
|
||||
#endif
|
||||
|
||||
static struct scst_dev_type disk_devtype = {
|
||||
.name = DISK_NAME,
|
||||
@@ -59,6 +64,10 @@ static struct scst_dev_type disk_devtype = {
|
||||
.attach = disk_attach,
|
||||
.detach = disk_detach,
|
||||
.parse = disk_parse,
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
.exec = disk_exec,
|
||||
.on_sg_tablesize_low = disk_on_sg_tablesize_low,
|
||||
#endif
|
||||
.dev_done = disk_done,
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -74,8 +83,11 @@ static struct scst_dev_type disk_devtype_perf = {
|
||||
.attach = disk_attach,
|
||||
.detach = disk_detach,
|
||||
.parse = disk_parse,
|
||||
.exec = disk_perf_exec,
|
||||
.dev_done = disk_done,
|
||||
.exec = disk_exec,
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
.on_sg_tablesize_low = disk_on_sg_tablesize_low,
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
.trace_flags = &trace_flag,
|
||||
@@ -145,15 +157,6 @@ static void __exit exit_scst_disk_driver(void)
|
||||
module_init(init_scst_disk_driver);
|
||||
module_exit(exit_scst_disk_driver);
|
||||
|
||||
/**************************************************************
|
||||
* Function: disk_attach
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns : 1 if attached, error code otherwise
|
||||
*
|
||||
* Description:
|
||||
*************************************************************/
|
||||
static int disk_attach(struct scst_device *dev)
|
||||
{
|
||||
int res, rc;
|
||||
@@ -260,15 +263,6 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Function: disk_detach
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns : None
|
||||
*
|
||||
* Description: Called to detach this device type driver
|
||||
************************************************************/
|
||||
static void disk_detach(struct scst_device *dev)
|
||||
{
|
||||
struct disk_params *params =
|
||||
@@ -293,17 +287,6 @@ static int disk_get_block_shift(struct scst_cmd *cmd)
|
||||
return params->block_shift;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Function: disk_parse
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns : The state of the command
|
||||
*
|
||||
* Description: This does the parsing of the command
|
||||
*
|
||||
* Note: Not all states are allowed on return
|
||||
********************************************************************/
|
||||
static int disk_parse(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_CMD_STATE_DEFAULT;
|
||||
@@ -329,17 +312,6 @@ static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift)
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Function: disk_done
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns :
|
||||
*
|
||||
* Description: This is the completion routine for the command,
|
||||
* it is used to extract any necessary information
|
||||
* about a command.
|
||||
********************************************************************/
|
||||
static int disk_done(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_CMD_STATE_DEFAULT;
|
||||
@@ -352,19 +324,315 @@ static int disk_done(struct scst_cmd *cmd)
|
||||
return res;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Function: disk_exec
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns :
|
||||
*
|
||||
* Description: Make SCST do nothing for data READs and WRITES.
|
||||
* Intended for raw line performance testing
|
||||
********************************************************************/
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
|
||||
static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd)
|
||||
{
|
||||
bool res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (cmd-> cdb[0]) {
|
||||
case WRITE_6:
|
||||
case READ_6:
|
||||
case WRITE_10:
|
||||
case READ_10:
|
||||
case WRITE_VERIFY:
|
||||
case WRITE_12:
|
||||
case READ_12:
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_16:
|
||||
case READ_16:
|
||||
case WRITE_VERIFY_16:
|
||||
res = true;
|
||||
/* See comment in disk_exec */
|
||||
cmd->inc_expected_sn_on_done = 1;
|
||||
break;
|
||||
default:
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct disk_work {
|
||||
struct scst_cmd *cmd;
|
||||
struct completion disk_work_cmpl;
|
||||
volatile int result;
|
||||
unsigned int left;
|
||||
uint64_t save_lba;
|
||||
unsigned int save_len;
|
||||
struct scatterlist *save_sg;
|
||||
int save_sg_cnt;
|
||||
};
|
||||
|
||||
static int disk_cdb_get_transfer_data(const uint8_t *cdb,
|
||||
uint64_t *out_lba, unsigned int *out_length)
|
||||
{
|
||||
int res;
|
||||
uint64_t lba;
|
||||
unsigned int len;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (cdb[0]) {
|
||||
case WRITE_6:
|
||||
case READ_6:
|
||||
lba = be16_to_cpu(get_unaligned((__be16 *)&cdb[2]));
|
||||
len = cdb[4];
|
||||
break;
|
||||
case WRITE_10:
|
||||
case READ_10:
|
||||
case WRITE_VERIFY:
|
||||
lba = be32_to_cpu(get_unaligned((__be32 *)&cdb[2]));
|
||||
len = be16_to_cpu(get_unaligned((__be16 *)&cdb[7]));
|
||||
break;
|
||||
case WRITE_12:
|
||||
case READ_12:
|
||||
case WRITE_VERIFY_12:
|
||||
lba = be32_to_cpu(get_unaligned((__be32 *)&cdb[2]));
|
||||
len = be32_to_cpu(get_unaligned((__be32 *)&cdb[6]));
|
||||
break;
|
||||
case WRITE_16:
|
||||
case READ_16:
|
||||
case WRITE_VERIFY_16:
|
||||
lba = be64_to_cpu(get_unaligned((__be64 *)&cdb[2]));
|
||||
len = be32_to_cpu(get_unaligned((__be32 *)&cdb[10]));
|
||||
break;
|
||||
default:
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
*out_lba = lba;
|
||||
*out_length = len;
|
||||
|
||||
TRACE_DBG("LBA %lld, length %d", (unsigned long long)lba, len);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int disk_cdb_set_transfer_data(uint8_t *cdb,
|
||||
uint64_t lba, unsigned int len)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (cdb[0]) {
|
||||
case WRITE_6:
|
||||
case READ_6:
|
||||
put_unaligned(cpu_to_be16(lba), (__be16 *)&cdb[2]);
|
||||
cdb[4] = len;
|
||||
break;
|
||||
case WRITE_10:
|
||||
case READ_10:
|
||||
case WRITE_VERIFY:
|
||||
put_unaligned(cpu_to_be32(lba), (__be32 *)&cdb[2]);
|
||||
put_unaligned(cpu_to_be16(len), (__be16 *)&cdb[7]);
|
||||
break;
|
||||
case WRITE_12:
|
||||
case READ_12:
|
||||
case WRITE_VERIFY_12:
|
||||
put_unaligned(cpu_to_be32(lba), (__be32 *)&cdb[2]);
|
||||
put_unaligned(cpu_to_be32(len), (__be32 *)&cdb[6]);
|
||||
break;
|
||||
case WRITE_16:
|
||||
case READ_16:
|
||||
case WRITE_VERIFY_16:
|
||||
put_unaligned(cpu_to_be64(lba), (__be64 *)&cdb[2]);
|
||||
put_unaligned(cpu_to_be32(len), (__be32 *)&cdb[10]);
|
||||
break;
|
||||
default:
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
TRACE_DBG("LBA %lld, length %d", (unsigned long long)lba, len);
|
||||
TRACE_BUFFER("New CDB", cdb, SCST_MAX_CDB_SIZE);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void disk_cmd_done(void *data, char *sense, int result, int resid)
|
||||
{
|
||||
struct disk_work *work = data;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("work %p, cmd %p, left %d, result %d, sense %p, resid %d",
|
||||
work, work->cmd, work->left, result, sense, resid);
|
||||
|
||||
if (result == SAM_STAT_GOOD)
|
||||
goto out_complete;
|
||||
|
||||
work->result = result;
|
||||
|
||||
disk_cdb_set_transfer_data(work->cmd->cdb, work->save_lba, work->save_len);
|
||||
work->cmd->sg = work->save_sg;
|
||||
work->cmd->sg_cnt = work->save_sg_cnt;
|
||||
|
||||
scst_pass_through_cmd_done(work->cmd, sense, result, resid + work->left);
|
||||
|
||||
out_complete:
|
||||
complete_all(&work->disk_work_cmpl);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Executes command and split CDB, if necessary */
|
||||
static int disk_exec(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_EXEC_NOT_COMPLETED, rc;
|
||||
int res, rc;
|
||||
struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv;
|
||||
struct disk_work work;
|
||||
unsigned int offset, cur_len;
|
||||
struct scatterlist *sg, *start_sg;
|
||||
int cur_sg_cnt;
|
||||
int sg_tablesize = cmd->dev->scsi_dev->host->sg_tablesize;
|
||||
int num, j;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (likely((cmd->sg_cnt <= sg_tablesize) &&
|
||||
(cmd->out_sg_cnt <= sg_tablesize))) {
|
||||
res = SCST_EXEC_NOT_COMPLETED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&work, 0, sizeof(work));
|
||||
work.cmd = cmd;
|
||||
work.save_sg = cmd->sg;
|
||||
work.save_sg_cnt = cmd->sg_cnt;
|
||||
rc = disk_cdb_get_transfer_data(cmd->cdb, &work.save_lba,
|
||||
&work.save_len);
|
||||
if (rc != 0)
|
||||
goto out_error;
|
||||
|
||||
rc = scst_check_local_events(cmd);
|
||||
if (unlikely(rc != 0))
|
||||
goto out_done;
|
||||
|
||||
cmd->status = 0;
|
||||
cmd->msg_status = 0;
|
||||
cmd->host_status = DID_OK;
|
||||
cmd->driver_status = 0;
|
||||
|
||||
TRACE_DBG("cmd %p, save_sg %p, save_sg_cnt %d, save_lba %lld, "
|
||||
"save_len %d (sg_tablesize %d, sizeof(*sg) 0x%x)", cmd,
|
||||
work.save_sg, work.save_sg_cnt,
|
||||
(unsigned long long)work.save_lba, work.save_len,
|
||||
sg_tablesize, sizeof(*sg));
|
||||
|
||||
/*
|
||||
* If we submit all chunks async'ly, it will be very not trivial what
|
||||
* to do if several of them finish with sense or residual. So, let's
|
||||
* do it synchronously.
|
||||
*/
|
||||
|
||||
num = 1;
|
||||
j = 0;
|
||||
offset = 0;
|
||||
cur_len = 0;
|
||||
sg = work.save_sg;
|
||||
start_sg = sg;
|
||||
cur_sg_cnt = 0;
|
||||
while (1) {
|
||||
unsigned int l;
|
||||
|
||||
if (unlikely(sg_is_chain(&sg[j]))) {
|
||||
bool reset_start_sg = (start_sg == &sg[j]);
|
||||
sg = sg_chain_ptr(&sg[j]);
|
||||
j = 0;
|
||||
if (reset_start_sg)
|
||||
start_sg = sg;
|
||||
}
|
||||
|
||||
l = sg[j].length >> params->block_shift;
|
||||
cur_len += l;
|
||||
cur_sg_cnt++;
|
||||
|
||||
TRACE_DBG("l %d, j %d, num %d, offset %d, cur_len %d, "
|
||||
"cur_sg_cnt %d, start_sg %p", l, j, num, offset,
|
||||
cur_len, cur_sg_cnt, start_sg);
|
||||
|
||||
if (((num % sg_tablesize) == 0) || (num == work.save_sg_cnt)) {
|
||||
TRACE_DBG("%s", "Execing...");
|
||||
|
||||
disk_cdb_set_transfer_data(cmd->cdb,
|
||||
work.save_lba + offset, cur_len);
|
||||
cmd->sg = start_sg;
|
||||
cmd->sg_cnt = cur_sg_cnt;
|
||||
|
||||
work.left = work.save_len - (offset + cur_len);
|
||||
init_completion(&work.disk_work_cmpl);
|
||||
|
||||
rc = scst_scsi_exec_async(cmd, &work, disk_cmd_done);
|
||||
if (unlikely(rc != 0)) {
|
||||
PRINT_ERROR("scst_scsi_exec_async() failed: %d",
|
||||
rc);
|
||||
goto out_err_restore;
|
||||
}
|
||||
|
||||
wait_for_completion(&work.disk_work_cmpl);
|
||||
|
||||
if (work.result != SAM_STAT_GOOD) {
|
||||
/* cmd can be already dead */
|
||||
res = SCST_EXEC_COMPLETED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset += cur_len;
|
||||
cur_len = 0;
|
||||
cur_sg_cnt = 0;
|
||||
start_sg = &sg[j+1];
|
||||
|
||||
if (num == work.save_sg_cnt)
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
j++;
|
||||
}
|
||||
|
||||
cmd->completed = 1;
|
||||
|
||||
out_restore:
|
||||
disk_cdb_set_transfer_data(cmd->cdb, work.save_lba, work.save_len);
|
||||
cmd->sg = work.save_sg;
|
||||
cmd->sg_cnt = work.save_sg_cnt;
|
||||
|
||||
out_done:
|
||||
res = SCST_EXEC_COMPLETED;
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_err_restore:
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_restore;
|
||||
|
||||
out_error:
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
|
||||
|
||||
static int disk_perf_exec(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
int opcode = cmd->cdb[0];
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -387,14 +655,21 @@ static int disk_exec(struct scst_cmd *cmd)
|
||||
case READ_10:
|
||||
case READ_12:
|
||||
case READ_16:
|
||||
cmd->completed = 1;
|
||||
goto out_done;
|
||||
case WRITE_VERIFY:
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_VERIFY_16:
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
res = SCST_EXEC_NOT_COMPLETED;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_complete:
|
||||
cmd->completed = 1;
|
||||
|
||||
out_done:
|
||||
res = SCST_EXEC_COMPLETED;
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
@@ -405,3 +680,4 @@ MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SCSI disk (type 0) dev handler for SCST");
|
||||
MODULE_VERSION(SCST_VERSION_STRING);
|
||||
|
||||
|
||||
@@ -4444,6 +4444,43 @@ void scst_release_request(struct scst_cmd *cmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool scst_on_sg_tablesize_low(struct scst_cmd *cmd, bool out)
|
||||
{
|
||||
bool res;
|
||||
int sg_cnt = out ? cmd->out_sg_cnt : cmd->sg_cnt;
|
||||
static int ll;
|
||||
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (sg_cnt > cmd->tgt->sg_tablesize) {
|
||||
/* It's the target's side business */
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (tgt_dev->dev->handler->on_sg_tablesize_low == NULL)
|
||||
goto failed;
|
||||
|
||||
res = tgt_dev->dev->handler->on_sg_tablesize_low(cmd);
|
||||
|
||||
TRACE_DBG("on_sg_tablesize_low(%p) returned %d", cmd, res);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
failed:
|
||||
res = false;
|
||||
if ((ll < 10) || TRACING_MINOR()) {
|
||||
PRINT_INFO("Unable to complete command due to SG IO count "
|
||||
"limitation (%srequested %d, available %d, tgt lim %d)",
|
||||
out ? "OUT buffer, " : "", cmd->sg_cnt,
|
||||
tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize);
|
||||
ll++;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
int scst_alloc_space(struct scst_cmd *cmd)
|
||||
{
|
||||
gfp_t gfp_mask;
|
||||
@@ -4451,7 +4488,6 @@ int scst_alloc_space(struct scst_cmd *cmd)
|
||||
int atomic = scst_cmd_atomic(cmd);
|
||||
int flags;
|
||||
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
|
||||
static int ll;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -4466,16 +4502,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
|
||||
if (cmd->sg == NULL)
|
||||
goto out;
|
||||
|
||||
if (unlikely(cmd->sg_cnt > tgt_dev->max_sg_cnt)) {
|
||||
if ((ll < 10) || TRACING_MINOR()) {
|
||||
PRINT_INFO("Unable to complete command due to "
|
||||
"SG IO count limitation (requested %d, "
|
||||
"available %d, tgt lim %d)", cmd->sg_cnt,
|
||||
tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize);
|
||||
ll++;
|
||||
}
|
||||
goto out_sg_free;
|
||||
}
|
||||
if (unlikely(cmd->sg_cnt > tgt_dev->max_sg_cnt))
|
||||
if (!scst_on_sg_tablesize_low(cmd, false))
|
||||
goto out_sg_free;
|
||||
|
||||
if (cmd->data_direction != SCST_DATA_BIDI)
|
||||
goto success;
|
||||
@@ -4486,16 +4515,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
|
||||
if (cmd->out_sg == NULL)
|
||||
goto out_sg_free;
|
||||
|
||||
if (unlikely(cmd->out_sg_cnt > tgt_dev->max_sg_cnt)) {
|
||||
if ((ll < 10) || TRACING_MINOR()) {
|
||||
PRINT_INFO("Unable to complete command due to "
|
||||
"SG IO count limitation (OUT buffer, requested "
|
||||
"%d, available %d, tgt lim %d)", cmd->out_sg_cnt,
|
||||
tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize);
|
||||
ll++;
|
||||
}
|
||||
goto out_out_sg_free;
|
||||
}
|
||||
if (unlikely(cmd->out_sg_cnt > tgt_dev->max_sg_cnt))
|
||||
if (!scst_on_sg_tablesize_low(cmd, true))
|
||||
goto out_out_sg_free;
|
||||
|
||||
success:
|
||||
res = 0;
|
||||
@@ -4718,10 +4740,11 @@ static void scsi_end_async(struct request *req, int error)
|
||||
/**
|
||||
* scst_scsi_exec_async - executes a SCSI command in pass-through mode
|
||||
* @cmd: scst command
|
||||
* @data: pointer passed to done() as "data"
|
||||
* @done: callback function when done
|
||||
*/
|
||||
int scst_scsi_exec_async(struct scst_cmd *cmd,
|
||||
void (*done)(void *, char *, int, int))
|
||||
int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
|
||||
void (*done)(void *data, char *sense, int result, int resid))
|
||||
{
|
||||
int res = 0;
|
||||
struct request_queue *q = cmd->dev->scsi_dev->request_queue;
|
||||
@@ -4806,7 +4829,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd,
|
||||
done:
|
||||
TRACE_DBG("sioc %p, cmd %p", sioc, cmd);
|
||||
|
||||
sioc->data = cmd;
|
||||
sioc->data = data;
|
||||
sioc->done = done;
|
||||
|
||||
rq->cmd_len = cmd_len;
|
||||
@@ -4844,6 +4867,7 @@ out_free_sioc:
|
||||
kfree(sioc);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_scsi_exec_async);
|
||||
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
|
||||
|
||||
|
||||
@@ -406,12 +406,9 @@ static inline int scst_exec_req(struct scsi_device *sdev,
|
||||
#endif
|
||||
}
|
||||
#else /* i.e. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */
|
||||
#if defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
int scst_scsi_exec_async(struct scst_cmd *cmd,
|
||||
void (*done)(void *, char *, int, int));
|
||||
#else
|
||||
static inline int scst_scsi_exec_async(struct scst_cmd *cmd,
|
||||
void (*done)(void *, char *, int, int))
|
||||
#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
|
||||
static inline int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
|
||||
void (*done)(void *data, char *sense, int result, int resid))
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return -1;
|
||||
|
||||
@@ -1568,7 +1568,15 @@ out:
|
||||
return;
|
||||
}
|
||||
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
|
||||
static void scst_cmd_done(void *data, char *sense, int result, int resid)
|
||||
|
||||
/**
|
||||
* scst_pass_through_cmd_done - done callback for pass-through commands
|
||||
* @data: private opaque data
|
||||
* @sense: pointer to the sense data, if any
|
||||
* @result: command's execution result
|
||||
* @resid: residual, if any
|
||||
*/
|
||||
void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid)
|
||||
{
|
||||
struct scst_cmd *cmd;
|
||||
|
||||
@@ -1589,6 +1597,8 @@ out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_pass_through_cmd_done);
|
||||
|
||||
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
|
||||
|
||||
static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state,
|
||||
@@ -2602,11 +2612,11 @@ static int scst_do_real_exec(struct scst_cmd *cmd)
|
||||
#else
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
|
||||
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,
|
||||
GFP_KERNEL);
|
||||
cmd->data_direction, cmd->sg, cmd->bufflen,
|
||||
cmd->sg_cnt, cmd->timeout, cmd->retries, cmd,
|
||||
scst_pass_through_cmd_done, GFP_KERNEL);
|
||||
#else
|
||||
rc = scst_scsi_exec_async(cmd, scst_cmd_done);
|
||||
rc = scst_scsi_exec_async(cmd, cmd, scst_pass_through_cmd_done);
|
||||
#endif
|
||||
if (unlikely(rc != 0)) {
|
||||
PRINT_ERROR("scst pass-through exec failed: %x", rc);
|
||||
@@ -4839,6 +4849,7 @@ static int scst_set_mcmd_next_state(struct scst_mgmt_cmd *mcmd)
|
||||
mcmd, mcmd->state, mcmd->fn,
|
||||
mcmd->cmd_finish_wait_count, mcmd->cmd_done_wait_count);
|
||||
spin_unlock_irq(&scst_mcmd_lock);
|
||||
res = -1;
|
||||
sBUG();
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1367,7 +1367,8 @@ static struct scsi_host_template scst_lcl_ini_driver_template = {
|
||||
.sg_tablesize = 0xFFFF,
|
||||
.cmd_per_lun = 32,
|
||||
.max_sectors = 0xffff,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
/* Possible pass-through backend device may not support clustering */
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.skip_settle_delay = 1,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user