mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
2042
scst/src/scst_lib.c
2042
scst/src/scst_lib.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user