Improve commands parsing and allow uniform LBA decoding as well as changing LBA and transfer length in uniform manner.

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4224 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2012-04-25 03:11:23 +00:00
parent 930135ee7b
commit 1d2a7e3364
11 changed files with 1586 additions and 894 deletions

View File

@@ -10,7 +10,7 @@ SCST user space device handler module interface descrition
<name>Vladislav Bolkhovitin</name>
</author>
<date>Version 2.1.0</date>
<date>Version 3.0.0</date>
<toc>
@@ -380,6 +380,7 @@ struct scst_user_scsi_cmd_reply_parse
uint8_t queue_type;
uint8_t data_direction;
uint16_t cdb_len;
aligned_i64 lba;
uint32_t op_flags;
int32_t data_len;
int32_t bufflen;
@@ -401,13 +402,17 @@ where:
<item> <bf/cdb_len/ - length of CDB
<item> <bf/lba/ - LBA of the command, if any
<item> <bf/op_flags/ - commands flags, one or more scst_cdb_flags bits, see above.
At least SCST_INFO_VALID must be set for correct processing.
SCST_IMPLICIT_HQ not implemented (yet) for single stage init target
drivers (all, except iSCSI), because custom parse can reorder
commands due to multithreaded processing.
<item> <bf/data_len/ - command's data length
<item> <bf/data_len/ - command's data length. Could be different from bufflen for
commands like VERIFY, which transfer different amount of data, than
process, or even none of them
<item> <bf/bufflen/ - command's buffer length
@@ -699,8 +704,11 @@ struct scst_user_scsi_cmd_parse
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
aligned_i64 lba;
uint32_t timeout;
int32_t bufflen;
int32_t data_len;
int32_t out_bufflen;
uint32_t op_flags;
@@ -726,10 +734,16 @@ where:
<item> <bf/cdb_len/ - SCSI CDB length
<item> <bf/lba/ - LBA of the command, if any
<item> <bf/timeout/ - CDB execution timeout
<item> <bf/bufflen/ - command's buffer length
<item> <bf/data_len/ - command's data length. Could be different from bufflen for
commands like VERIFY, which transfer different amount of data, than
process, or even none of them
<item> <bf/out_bufflen/ - for bidirectional commands command's OUT, i.e. from
initiator to target, buffer length
@@ -920,6 +934,8 @@ struct scst_user_scsi_cmd_exec
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
aligned_i64 lba;
int32_t data_len;
int32_t bufflen;
int32_t alloc_len;
@@ -949,6 +965,8 @@ where:
<item> <bf/cdb_len/ - SCSI CDB length
<item> <bf/lba/ - LBA of the command, if any
<item> <bf/data_len/ - command's data length. Could be different from bufflen for
commands like VERIFY, which transfer different amount of data, than
process, or even none of them

View File

@@ -1978,8 +1978,12 @@ struct scst_cmd {
unsigned short cdb_len;
uint8_t cdb_buf[SCST_MAX_CDB_SIZE];
enum scst_cdb_flags op_flags;
const char *op_name;
uint8_t lba_off; /* LBA offset in cdb */
uint8_t lba_len; /* LBA length in cdb */
uint8_t len_off; /* length offset in cdb */
uint8_t len_len; /* length length in cdb */
uint32_t op_flags; /* various flags of this opcode */
const char *op_name; /* op code SCSI full name */
enum scst_cmd_queue_type queue_type;
@@ -2006,9 +2010,10 @@ struct scst_cmd {
enum scst_exec_context pref_context);
struct sgv_pool_obj *sgv; /* sgv object */
int64_t lba; /* LBA of this cmd in blocks */
int bufflen; /* cmd buffer length */
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
struct scatterlist *sg; /* cmd data buffer SG vector */
/*
* Response data length in data buffer. Must not be set
@@ -3109,6 +3114,12 @@ static inline int scst_cmd_get_sg_cnt(struct scst_cmd *cmd)
return cmd->sg_cnt;
}
/* Returns cmd's LBA */
static inline int64_t scst_cmd_get_lba(struct scst_cmd *cmd)
{
return cmd->lba;
}
/*
* Returns cmd's data buffer length.
*
@@ -3116,11 +3127,20 @@ static inline int scst_cmd_get_sg_cnt(struct scst_cmd *cmd)
* this function is not recommended, use scst_get_buf_*()
* family of functions instead.
*/
static inline unsigned int scst_cmd_get_bufflen(struct scst_cmd *cmd)
static inline int scst_cmd_get_bufflen(struct scst_cmd *cmd)
{
return cmd->bufflen;
}
/*
* Returns cmd's data_len. See the corresponding field's description in
* struct scst_cmd above.
*/
static inline int scst_cmd_get_data_len(struct scst_cmd *cmd)
{
return cmd->data_len;
}
/*
* Returns pointer to cmd's bidirectional in (WRITE) SG data buffer.
*
@@ -3514,6 +3534,9 @@ static inline unsigned int scst_get_active_cmd_count(struct scst_cmd *cmd)
return (unsigned int)-1;
}
int scst_set_cdb_lba(struct scst_cmd *cmd, int64_t len);
int scst_set_cdb_transf_len(struct scst_cmd *cmd, int len);
/*
* Get/Set function for mgmt cmd's target private data
*/

View File

@@ -183,8 +183,9 @@ enum scst_cdb_flags {
SCST_TRANSFER_LEN_TYPE_FIXED = 0x0001,
SCST_SMALL_TIMEOUT = 0x0002,
SCST_LONG_TIMEOUT = 0x0004,
SCST_UNKNOWN_LENGTH = 0x0008,
SCST_INFO_VALID = 0x0010, /* must be single bit */
SCST_UNKNOWN_LBA = 0x0008,
SCST_UNKNOWN_LENGTH = 0x0010,
SCST_INFO_VALID = 0x0020, /* must be single bit */
SCST_IMPLICIT_HQ = 0x0040,
SCST_SKIP_UA = 0x0080,
SCST_WRITE_MEDIUM = 0x0100,

View File

@@ -60,6 +60,10 @@
#define aligned_u64 uint64_t __attribute__((aligned(8)))
#endif
#ifndef aligned_i64
#define aligned_i64 int64_t __attribute__((aligned(8)))
#endif
/*************************************************************
** Private ucmd states
*************************************************************/
@@ -125,8 +129,11 @@ struct scst_user_scsi_cmd_parse {
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
aligned_i64 lba;
int32_t timeout;
int32_t bufflen;
int32_t data_len;
int32_t out_bufflen;
uint32_t op_flags;
@@ -162,6 +169,8 @@ struct scst_user_scsi_cmd_exec {
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
aligned_i64 lba;
int32_t data_len;
int32_t bufflen;
int32_t alloc_len;
@@ -225,6 +234,7 @@ struct scst_user_scsi_cmd_reply_parse {
uint8_t queue_type;
uint8_t data_direction;
uint16_t cdb_len;
aligned_i64 lba;
uint32_t op_flags;
int32_t data_len;
int32_t bufflen;

View File

@@ -368,110 +368,16 @@ struct disk_work {
struct completion disk_work_cmpl;
int result;
unsigned int left;
uint64_t save_lba;
unsigned int save_len;
int64_t save_lba;
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 = get_unaligned_be16(&cdb[2]);
len = cdb[4];
break;
case WRITE_10:
case READ_10:
case WRITE_VERIFY:
lba = get_unaligned_be32(&cdb[2]);
len = get_unaligned_be16(&cdb[7]);
break;
case WRITE_12:
case READ_12:
case WRITE_VERIFY_12:
lba = get_unaligned_be32(&cdb[2]);
len = get_unaligned_be32(&cdb[6]);
break;
case WRITE_16:
case READ_16:
case WRITE_VERIFY_16:
lba = get_unaligned_be64(&cdb[2]);
len = 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_be16(lba, &cdb[2]);
cdb[4] = len;
break;
case WRITE_10:
case READ_10:
case WRITE_VERIFY:
put_unaligned_be32(lba, &cdb[2]);
put_unaligned_be16(len, &cdb[7]);
break;
case WRITE_12:
case READ_12:
case WRITE_VERIFY_12:
put_unaligned_be32(lba, &cdb[2]);
put_unaligned_be32(len, &cdb[6]);
break;
case WRITE_16:
case READ_16:
case WRITE_VERIFY_16:
put_unaligned_be64(lba, &cdb[2]);
put_unaligned_be32(len, &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_restore_sg(struct disk_work *work)
{
disk_cdb_set_transfer_data(work->cmd->cdb, work->save_lba, work->save_len);
scst_set_cdb_lba(work->cmd, work->save_lba);
scst_set_cdb_transf_len(work->cmd, work->save_len);
work->cmd->sg = work->save_sg;
work->cmd->sg_cnt = work->save_sg_cnt;
return;
@@ -546,7 +452,7 @@ static int disk_exec(struct scst_cmd *cmd)
goto split;
}
if (likely(cmd->sg_cnt <= sg_tablesize)) {
if (cmd->sg_cnt <= sg_tablesize) {
res = SCST_EXEC_NOT_COMPLETED;
goto out;
}
@@ -564,10 +470,10 @@ split:
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;
work.save_lba = cmd->lba;
work.save_len = cmd->bufflen;
EXTRACHECKS_BUG_ON(work.save_len < 0);
cmd->status = 0;
cmd->msg_status = 0;
@@ -617,8 +523,8 @@ split:
(cur_len >= max_sectors)) {
TRACE_DBG("%s", "Execing...");
disk_cdb_set_transfer_data(cmd->cdb,
work.save_lba + offset, cur_len);
scst_set_cdb_lba(work.cmd, work.save_lba + offset);
scst_set_cdb_transf_len(work.cmd, cur_len);
cmd->sg = start_sg;
cmd->sg_cnt = cur_sg_cnt;

View File

@@ -808,7 +808,9 @@ static int dev_user_parse(struct scst_cmd *cmd)
min_t(int, SCST_MAX_CDB_SIZE, cmd->cdb_len));
ucmd->user_cmd.parse_cmd.cdb_len = cmd->cdb_len;
ucmd->user_cmd.parse_cmd.timeout = cmd->timeout / HZ;
ucmd->user_cmd.parse_cmd.lba = cmd->lba;
ucmd->user_cmd.parse_cmd.bufflen = cmd->bufflen;
ucmd->user_cmd.parse_cmd.data_len = cmd->data_len;
ucmd->user_cmd.parse_cmd.out_bufflen = cmd->out_bufflen;
ucmd->user_cmd.parse_cmd.queue_type = cmd->queue_type;
ucmd->user_cmd.parse_cmd.data_direction = cmd->data_direction;
@@ -913,9 +915,9 @@ static int dev_user_exec(struct scst_cmd *cmd)
TRACE_ENTRY();
TRACE_DBG("Preparing EXEC for user space (ucmd=%p, h=%d, "
TRACE_DBG("Preparing EXEC for user space (ucmd=%p, h=%d, lba %lld, "
"bufflen %d, data_len %d, ubuff %lx)", ucmd, ucmd->h,
cmd->bufflen, cmd->data_len, ucmd->ubuff);
(long long)cmd->lba, cmd->bufflen, cmd->data_len, ucmd->ubuff);
if (cmd->data_direction & SCST_DATA_WRITE)
dev_user_flush_dcache(ucmd);
@@ -929,6 +931,7 @@ static int dev_user_exec(struct scst_cmd *cmd)
memcpy(ucmd->user_cmd.exec_cmd.cdb, cmd->cdb,
min_t(int, SCST_MAX_CDB_SIZE, cmd->cdb_len));
ucmd->user_cmd.exec_cmd.cdb_len = cmd->cdb_len;
ucmd->user_cmd.exec_cmd.lba = cmd->lba;
ucmd->user_cmd.exec_cmd.bufflen = cmd->bufflen;
ucmd->user_cmd.exec_cmd.data_len = cmd->data_len;
ucmd->user_cmd.exec_cmd.pbuf = ucmd->ubuff;
@@ -1299,7 +1302,7 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd,
goto out_inval;
if (unlikely((preply->bufflen < 0) || (preply->out_bufflen < 0) ||
(preply->data_len < 0)))
(preply->data_len < 0) || (preply->lba < 0)))
goto out_inval;
if (unlikely(preply->cdb_len > cmd->cdb_len))
@@ -1308,14 +1311,15 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd,
if (!(preply->op_flags & SCST_INFO_VALID))
goto out_inval;
TRACE_DBG("ucmd %p, queue_type %x, data_direction, %x, bufflen %d, "
"data_len %d, pbuf %llx, cdb_len %d, op_flags %x", ucmd,
preply->queue_type, preply->data_direction, preply->bufflen,
preply->data_len, reply->alloc_reply.pbuf, preply->cdb_len,
preply->op_flags);
TRACE_DBG("ucmd %p, queue_type %x, data_direction, %x, lba %lld, "
"bufflen %d, data_len %d, pbuf %llx, cdb_len %d, op_flags %x",
ucmd, preply->queue_type, preply->data_direction,
(long long)preply->lba, preply->bufflen, preply->data_len,
reply->alloc_reply.pbuf, preply->cdb_len, preply->op_flags);
cmd->queue_type = preply->queue_type;
cmd->data_direction = preply->data_direction;
cmd->lba = preply->lba;
cmd->bufflen = preply->bufflen;
cmd->out_bufflen = preply->out_bufflen;
cmd->data_len = preply->data_len;

View File

@@ -191,9 +191,7 @@ struct vdisk_cmd_params {
int iv_count;
struct iovec small_iv[4];
struct scst_cmd *cmd;
uint64_t lba_start;
loff_t loff;
loff_t data_len;
int fua;
bool use_zero_copy;
};
@@ -974,7 +972,7 @@ static enum compl_status_e vdisk_synchronize_cache(struct vdisk_cmd_params *p)
const uint8_t *cdb = cmd->cdb;
struct scst_device *dev = cmd->dev;
const loff_t loff = p->loff;
const loff_t data_len = p->data_len;
int data_len = scst_cmd_get_data_len(cmd);
int immed = cdb[1] & 0x2;
enum compl_status_e res;
@@ -985,6 +983,12 @@ static enum compl_status_e vdisk_synchronize_cache(struct vdisk_cmd_params *p)
(long long unsigned int)loff,
(long long unsigned int)data_len, immed);
if (data_len == 0) {
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
data_len = virt_dev->file_size -
((loff_t)scst_cmd_get_lba(cmd) << virt_dev->block_shift);
}
if (immed) {
scst_cmd_get(cmd); /* to protect dev */
cmd->completed = 1;
@@ -1116,13 +1120,13 @@ static const vdisk_op_fn nullio_ops[256] = {
};
/*
* Compute p->lba_start, p->loff, p->data_len and p->fua.
* Compute p->loff and p->fua.
* Returns true for success or false otherwise and set error in the commeand.
*/
static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
{
uint64_t lba_start = 0;
loff_t data_len = 0;
uint64_t lba_start;
int data_len;
uint8_t *cdb = cmd->cdb;
int opcode = cdb[0];
loff_t loff;
@@ -1133,6 +1137,14 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
TRACE_ENTRY();
if (unlikely(!(cmd->op_flags & SCST_INFO_VALID))) {
PRINT_ERROR("Unknown opcode 0x%02x", cmd->cdb[0]);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
res = false;
goto out;
}
p->cmd = cmd;
cmd->status = 0;
@@ -1151,55 +1163,8 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
break;
}
switch (opcode) {
case READ_6:
case WRITE_6:
lba_start = get_unaligned_be24(&cdb[1]) & 0x1f0000U;
data_len = cmd->bufflen;
use_zero_copy = true;
break;
case READ_10:
case READ_12:
case WRITE_10:
case WRITE_12:
case WRITE_VERIFY:
case WRITE_VERIFY_12:
lba_start = get_unaligned_be32(&cdb[2]);
data_len = cmd->bufflen;
use_zero_copy = true;
break;
case READ_16:
case WRITE_16:
case WRITE_VERIFY_16:
lba_start = get_unaligned_be64(&cdb[2]);
data_len = cmd->bufflen;
use_zero_copy = true;
break;
case VERIFY:
lba_start = get_unaligned_be32(&cdb[2]);
data_len = get_unaligned_be16(&cdb[7]) << virt_dev->block_shift;
use_zero_copy = true;
break;
case VERIFY_12:
lba_start = get_unaligned_be32(&cdb[2]);
data_len = get_unaligned_be32(&cdb[6]) << virt_dev->block_shift;
use_zero_copy = true;
break;
case VERIFY_16:
lba_start = get_unaligned_be64(&cdb[2]);
data_len = get_unaligned_be32(&cdb[10]) << virt_dev->block_shift;
use_zero_copy = true;
break;
case SYNCHRONIZE_CACHE:
lba_start = get_unaligned_be32(&cdb[2]);
data_len = get_unaligned_be16(&cdb[7]) << virt_dev->block_shift;
if (data_len == 0)
data_len = virt_dev->file_size -
((loff_t)lba_start << virt_dev->block_shift);
break;
}
p->use_zero_copy = use_zero_copy && virt_dev->zero_copy;
lba_start = scst_cmd_get_lba(cmd);
data_len = scst_cmd_get_data_len(cmd);
loff = (loff_t)lba_start << virt_dev->block_shift;
TRACE_DBG("cmd %p, lba_start %lld, loff %lld, data_len %lld", cmd,
@@ -1209,7 +1174,7 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
if (unlikely(loff < 0) || unlikely(data_len < 0) ||
unlikely((loff + data_len) > virt_dev->file_size)) {
PRINT_INFO("Access beyond the end of the device "
"(%lld of %lld, len %lld)",
"(%lld of %lld, data len %lld)",
(long long unsigned int)loff,
(long long unsigned int)virt_dev->file_size,
(long long unsigned int)data_len);
@@ -1219,6 +1184,15 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
goto out;
}
switch (opcode) {
case READ_6:
case READ_10:
case READ_12:
case READ_16:
use_zero_copy = true;
break;
}
switch (opcode) {
case WRITE_10:
case WRITE_12:
@@ -1232,10 +1206,9 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
break;
}
p->lba_start = lba_start;
p->data_len = data_len;
p->loff = loff;
p->fua = fua;
p->use_zero_copy = use_zero_copy && virt_dev->zero_copy;
res = true;
@@ -3545,7 +3518,7 @@ restart:
out_sync:
/* O_SYNC flag is used for WT devices */
if (p->fua)
vdisk_fsync(p, loff, p->data_len, cmd->dev,
vdisk_fsync(p, loff, scst_cmd_get_data_len(cmd), cmd->dev,
scst_cmd_get_gfp_flags(cmd), cmd);
out:
TRACE_EXIT();
@@ -3638,7 +3611,7 @@ static void blockio_endio(struct bio *bio, int error)
static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
{
struct scst_cmd *cmd = p->cmd;
u64 lba_start = p->lba_start;
u64 lba_start = scst_cmd_get_lba(cmd);
struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv;
struct block_device *bdev = virt_dev->bdev;
struct request_queue *q = bdev_get_queue(bdev);
@@ -3831,12 +3804,13 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv;
struct file *fd = virt_dev->fd;
uint8_t *mem_verify = NULL;
int data_len = scst_cmd_get_data_len(cmd);
TRACE_ENTRY();
sBUG_ON(virt_dev->blockio);
if (vdisk_fsync(p, loff, cmd->bufflen, cmd->dev,
if (vdisk_fsync(p, loff, data_len, cmd->dev,
scst_cmd_get_gfp_flags(cmd), cmd) != 0)
goto out;
@@ -3849,8 +3823,8 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
*/
compare = scst_cmd_get_data_direction(cmd) == SCST_DATA_WRITE;
TRACE_DBG("VERIFY with BYTCHK=%d at offset %lld and with len = %lld\n",
compare, loff, p->data_len);
TRACE_DBG("VERIFY with BYTCHK=%d at offset %lld and len %d\n",
compare, loff, data_len);
/* SEEK */
old_fs = get_fs();
@@ -3875,17 +3849,15 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
if (mem_verify == NULL) {
PRINT_ERROR("Unable to allocate memory %d for verify",
LEN_MEM);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out_set_fs;
}
if (compare) {
length = scst_get_buf_first(cmd, &address);
address_sav = address;
} else {
length = p->data_len;
}
} else
length = data_len;
while (length > 0) {
len_mem = (length > LEN_MEM) ? LEN_MEM : length;

File diff suppressed because it is too large Load Diff

View File

@@ -109,6 +109,8 @@ extern unsigned long scst_trace_flag;
#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ)
#define SCST_DEF_DATA_LEN -1
extern struct mutex scst_mutex2;
extern int scst_threads;

View File

@@ -505,14 +505,14 @@ int scst_pre_parse(struct scst_cmd *cmd)
cmd->queue_type == SCST_CMD_QUEUE_ORDERED));
#endif
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
"(expected %d, set %s), bufflen=%d, out_bufflen=%d (expected "
"len %d, out expected len %d), flags=0x%x", cmd->op_name, cmd,
cmd->data_direction, cmd->expected_data_direction,
"(expected %d, set %s), bufflen=%d, data_len %d, out_bufflen=%d "
"(expected len %d, out expected len %d), flags=0x%x", cmd->op_name,
cmd, cmd->data_direction, cmd->expected_data_direction,
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
cmd->bufflen, cmd->out_bufflen, cmd->expected_transfer_len,
cmd->expected_out_transfer_len, cmd->op_flags);
cmd->bufflen, cmd->data_len, cmd->out_bufflen,
cmd->expected_transfer_len, cmd->expected_out_transfer_len,
cmd->op_flags);
res = 0;
@@ -611,6 +611,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
cmd->expected_out_transfer_len);
cmd->data_direction = cmd->expected_data_direction;
cmd->bufflen = cmd->expected_transfer_len;
cmd->data_len = cmd->bufflen;
cmd->out_bufflen = cmd->expected_out_transfer_len;
} else {
PRINT_ERROR("Unknown opcode 0x%02x for %s and "
@@ -649,14 +650,6 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
EXTRACHECKS_BUG_ON(cmd->cdb_len == 0);
TRACE(TRACE_SCSI, "op_name <%s> (cmd %p), direction=%d "
"(expected %d, set %s), bufflen=%d, out_bufflen=%d, (expected "
"len %d, out expected len %d), flags=%x", cmd->op_name, cmd,
cmd->data_direction, cmd->expected_data_direction,
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
cmd->bufflen, cmd->out_bufflen, cmd->expected_transfer_len,
cmd->expected_out_transfer_len, cmd->op_flags);
if (unlikely((cmd->op_flags & SCST_UNKNOWN_LENGTH) != 0)) {
if (scst_cmd_is_expected_set(cmd)) {
/*
@@ -669,6 +662,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
*/
cmd->bufflen = min(cmd->expected_transfer_len,
15*1024*1024);
cmd->data_len = cmd->bufflen;
if (cmd->data_direction == SCST_DATA_BIDI)
cmd->out_bufflen = min(cmd->expected_out_transfer_len,
15*1024*1024);
@@ -741,6 +735,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
cmd->cdb, cmd->cdb_len);
cmd->data_direction = cmd->expected_data_direction;
cmd->bufflen = cmd->expected_transfer_len;
cmd->data_len = cmd->bufflen;
cmd->out_bufflen = cmd->expected_out_transfer_len;
cmd->resid_possible = 1;
}
@@ -799,10 +794,14 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
goto out_hw_error;
}
set_res:
if (cmd->data_len == -1)
cmd->data_len = cmd->bufflen;
if (unlikely(cmd->op_flags & SCST_UNKNOWN_LBA)) {
PRINT_ERROR("Unknown LBA (opcode 0x%x, handler %s, "
"target %s)", cmd->cdb[0], devt->name, cmd->tgtt->name);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
goto out_hw_error;
}
set_res:
if (cmd->bufflen == 0) {
/*
* According to SPC bufflen 0 for data transfer commands isn't
@@ -811,6 +810,15 @@ set_res:
cmd->data_direction = SCST_DATA_NONE;
}
TRACE(TRACE_SCSI, "op_name <%s> (cmd %p), direction=%d "
"(expected %d, set %s), bufflen=%d, data len %d, out_bufflen=%d, "
"(expected len %d, out expected len %d), flags=0x%x, lba=%lld",
cmd->op_name, cmd, cmd->data_direction, cmd->expected_data_direction,
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
cmd->bufflen, cmd->data_len, cmd->out_bufflen,
cmd->expected_transfer_len, cmd->expected_out_transfer_len,
cmd->op_flags, (unsigned long long)cmd->lba);
#ifdef CONFIG_SCST_EXTRACHECKS
switch (state) {
case SCST_CMD_STATE_PREPARE_SPACE:
@@ -871,6 +879,23 @@ set_res:
#endif
out:
#ifdef CONFIG_SCST_EXTRACHECKS
/*
* At this point either data_len must be initialized, or cmd
* completed (with an error).
*/
if (unlikely((cmd->data_len == SCST_DEF_DATA_LEN)) &&
(!cmd->completed || ((cmd->state <= SCST_CMD_STATE_REAL_EXEC) &&
(cmd->state != SCST_CMD_STATE_PREPROCESSING_DONE)))) {
PRINT_CRIT_ERROR("Not initialized data_len for going to "
"execute command (cmd %p, data_len %d, completed %d, "
"state %d)", cmd, cmd->data_len, cmd->completed,
cmd->state);
WARN_ON(1);
goto out_hw_error;
}
#endif
TRACE_EXIT_HRES(res);
return res;
@@ -950,8 +975,8 @@ static int scst_prepare_space(struct scst_cmd *cmd)
goto out;
}
TRACE_DBG("Calling dev handler %s (%p) alloc_data_buf(%p)",
devt->name, devt, cmd);
TRACE_DBG("Calling dev handler's %s alloc_data_buf(%p)",
devt->name, cmd);
scst_set_cur_start(cmd);
state = devt->alloc_data_buf(cmd);
/*
@@ -2701,6 +2726,8 @@ static int scst_pre_exec_checks(struct scst_cmd *cmd)
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(cmd->data_len == SCST_DEF_DATA_LEN);
rc = __scst_check_local_events(cmd, false);
if (unlikely(rc != 0))
goto out_done;

View File

@@ -123,6 +123,7 @@ static int do_parse(struct vdisk_cmd *vcmd)
reply->queue_type = cmd->queue_type;
reply->data_direction = cmd->expected_data_direction;
reply->lba = cmd->lba;
reply->data_len = cmd->expected_transfer_len;
reply->bufflen = cmd->expected_transfer_len;
reply->out_bufflen = cmd->expected_out_transfer_len;
@@ -177,8 +178,8 @@ static int do_exec(struct vdisk_cmd *vcmd)
struct vdisk_dev *dev = vcmd->dev;
struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
uint64_t lba_start = 0;
loff_t data_len = 0;
uint64_t lba_start = cmd->lba;
loff_t data_len = cmd->data_len;
uint8_t *cdb = cmd->cdb;
int opcode = cdb[0];
loff_t loff;
@@ -241,55 +242,6 @@ static int do_exec(struct vdisk_cmd *vcmd)
if (cmd->data_direction & SCST_DATA_READ)
reply->resp_data_len = cmd->bufflen;
switch (opcode) {
case READ_6:
case WRITE_6:
lba_start = (((cdb[1] & 0x1f) << (BYTE * 2)) +
(cdb[2] << (BYTE * 1)) +
(cdb[3] << (BYTE * 0)));
data_len = cmd->bufflen;
break;
case READ_10:
case READ_12:
case WRITE_10:
case WRITE_12:
case VERIFY:
case WRITE_VERIFY:
case WRITE_VERIFY_12:
case VERIFY_12:
lba_start |= ((uint64_t)cdb[2]) << 24;
lba_start |= ((uint64_t)cdb[3]) << 16;
lba_start |= ((uint64_t)cdb[4]) << 8;
lba_start |= ((uint64_t)cdb[5]);
data_len = cmd->bufflen;
break;
case SYNCHRONIZE_CACHE:
lba_start |= ((uint64_t)cdb[2]) << 24;
lba_start |= ((uint64_t)cdb[3]) << 16;
lba_start |= ((uint64_t)cdb[4]) << 8;
lba_start |= ((uint64_t)cdb[5]);
data_len = ((cdb[7] << (BYTE * 1)) + (cdb[8] << (BYTE * 0)))
<< dev->block_shift;
if (data_len == 0)
data_len = dev->file_size -
((loff_t)lba_start << dev->block_shift);
break;
case READ_16:
case WRITE_16:
case WRITE_VERIFY_16:
case VERIFY_16:
lba_start |= ((uint64_t)cdb[2]) << 56;
lba_start |= ((uint64_t)cdb[3]) << 48;
lba_start |= ((uint64_t)cdb[4]) << 40;
lba_start |= ((uint64_t)cdb[5]) << 32;
lba_start |= ((uint64_t)cdb[6]) << 24;
lba_start |= ((uint64_t)cdb[7]) << 16;
lba_start |= ((uint64_t)cdb[8]) << 8;
lba_start |= ((uint64_t)cdb[9]);
data_len = cmd->bufflen;
break;
}
loff = (loff_t)lba_start << dev->block_shift;
TRACE_DBG("cmd %d, buf %"PRIx64", lba_start %"PRId64", loff %"PRId64
", data_len %"PRId64, vcmd->cmd->cmd_h, cmd->pbuf, lba_start,
@@ -381,6 +333,9 @@ static int do_exec(struct vdisk_cmd *vcmd)
case SYNCHRONIZE_CACHE:
{
int immed = cdb[1] & 0x2;
if (data_len == 0)
data_len = dev->file_size -
((loff_t)lba_start << dev->block_shift);
TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: "
"loff=%"PRId64", data_len=%"PRId64", immed=%d",
(uint64_t)loff, (uint64_t)data_len, immed);
@@ -1658,7 +1613,7 @@ static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff)
struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
loff_t err;
int length = cmd->bufflen;
uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
uint8_t *address = (uint8_t *)(unsigned long)cmd->pbuf;
int compare;
int fd = vcmd->fd;
uint8_t mem_verify[128*1024];