Unify parsing of descriptors-based and internal commands

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4290 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2012-05-07 22:39:54 +00:00
parent 7596ffd7dd
commit 3b57904da6
6 changed files with 236 additions and 58 deletions
+15 -1
View File
@@ -2114,6 +2114,15 @@ struct scst_cmd {
/* Counter of the corresponding SCST_PR_ABORT_ALL TM commands */
struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_abort_counter;
/*
* List of parsed data descriptors for commands operating with
* several lba and data_len pairs, like UNMAP.
*/
void *cmd_data_descriptors;
/* Count of entries in the descriptors array */
int cmd_data_descriptors_cnt;
#ifdef CONFIG_SCST_MEASURE_LATENCY
/*
* Must be the last to allow to work with drivers who don't know
@@ -2407,7 +2416,7 @@ struct scst_device {
/* List of blocked commands, protected by dev_lock. */
struct list_head blocked_cmd_list;
/* A list entry used during TM, protected by scst_mutex */
/* A list entry used during TM */
struct list_head tm_dev_list_entry;
int virt_id; /* virtual device internal ID */
@@ -4399,4 +4408,9 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
void scst_write_same(struct scst_cmd *cmd);
struct scst_data_descriptor {
uint64_t sdd_lba;
uint64_t sdd_len;
};
#endif /* __SCST_H */
+2 -1
View File
@@ -198,7 +198,8 @@ enum scst_cdb_flags {
SCST_TEST_IO_IN_SIRQ_ALLOWED = 0x4000,
#endif
SCST_SERIALIZED = 0x8000,
SCST_STRICTLY_SERIALIZED = 0x10000|SCST_SERIALIZED,
SCST_STRICTLY_SERIALIZED = 0x10000|SCST_SERIALIZED,
SCST_DESCRIPTORS_BASED = 0x20000,
};
/*************************************************************
+7 -46
View File
@@ -2013,9 +2013,8 @@ static enum compl_status_e vdisk_exec_unmap(struct vdisk_cmd_params *p)
{
struct scst_cmd *cmd = p->cmd;
struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv;
ssize_t length = 0;
uint8_t *address;
int offset, descriptor_len, total_len;
struct scst_data_descriptor *pd = cmd->cmd_data_descriptors;
int i;
TRACE_ENTRY();
@@ -2033,54 +2032,16 @@ static enum compl_status_e vdisk_exec_unmap(struct vdisk_cmd_params *p)
goto out;
}
length = scst_get_buf_full(cmd, &address);
if (unlikely(length <= 0)) {
if (length == 0)
goto out_put;
else if (length == -ENOMEM)
scst_set_busy(cmd);
else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
if (pd == NULL)
goto out;
}
total_len = get_unaligned_be16(&cmd->cdb[7]); /* length */
offset = 8;
descriptor_len = get_unaligned_be16(&address[2]);
TRACE_DBG("total_len %d, descriptor_len %d", total_len, descriptor_len);
if (descriptor_len == 0)
goto out_put;
if (unlikely((descriptor_len > (total_len - 8)) ||
((descriptor_len % 16) != 0))) {
PRINT_ERROR("Bad descriptor length: %d < %d - 8",
descriptor_len, total_len);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
goto out_put;
}
while ((offset - 8) < descriptor_len) {
int rc;
uint64_t start;
uint32_t len;
start = get_unaligned_be64(&address[offset]);
offset += 8;
len = get_unaligned_be32(&address[offset]);
offset += 8;
rc = vdisk_unmap_range(cmd, virt_dev, start, len);
for (i = 0; i < cmd->cmd_data_descriptors_cnt; i++) {
struct scst_data_descriptor *d = &pd[i];
int rc = vdisk_unmap_range(cmd, virt_dev, d->sdd_lba, d->sdd_len);
if (rc != 0)
goto out_put;
goto out;
}
out_put:
scst_put_buf_full(cmd, address);
out:
TRACE_EXIT();
+195 -3
View File
@@ -73,6 +73,7 @@ static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
enum km_type d_km_type, enum km_type s_km_type);
#endif
static void scst_free_descriptors(struct scst_cmd *cmd);
static void scst_destroy_put_cmd(struct scst_cmd *cmd);
struct scst_sdbops;
@@ -685,7 +686,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{.ops = 0x42, .devkey = "O ",
.info_op_name = "UNMAP",
.info_data_direction = SCST_DATA_WRITE,
.info_op_flags = SCST_WRITE_MEDIUM,
.info_op_flags = SCST_WRITE_MEDIUM|SCST_DESCRIPTORS_BASED,
.info_len_off = 7, .info_len_len = 2,
.get_cdb_info = get_cdb_info_len_2},
{.ops = 0x43, .devkey = " O ",
@@ -4766,7 +4767,7 @@ int scst_finish_internal_cmd(struct scst_cmd *cmd)
if (cmd->cdb[0] == REQUEST_SENSE)
scst_complete_request_sense(cmd);
else if (cmd->cdb[0] == WRITE_16) {
else {
struct scst_i_finish_t *f = cmd->tgt_i_priv;
f->scst_i_finish_fn(cmd);
}
@@ -5230,6 +5231,9 @@ void scst_free_cmd(struct scst_cmd *cmd)
}
}
if (unlikely(cmd->op_flags & SCST_DESCRIPTORS_BASED))
scst_free_descriptors(cmd);
if (cmd->cdb != cmd->cdb_buf)
kfree(cmd->cdb);
@@ -6724,6 +6728,57 @@ int scst_raid_generic_parse(struct scst_cmd *cmd)
}
EXPORT_SYMBOL_GPL(scst_raid_generic_parse);
int scst_do_internal_parsing(struct scst_cmd *cmd)
{
int res, rc;
TRACE_ENTRY();
switch (cmd->dev->type) {
case TYPE_DISK:
rc = scst_sbc_generic_parse(cmd);
break;
case TYPE_TAPE:
rc = scst_tape_generic_parse(cmd);
break;
case TYPE_PROCESSOR:
rc = scst_processor_generic_parse(cmd);
break;
case TYPE_ROM:
rc = scst_cdrom_generic_parse(cmd);
break;
case TYPE_MOD:
rc = scst_modisk_generic_parse(cmd);
break;
case TYPE_MEDIUM_CHANGER:
rc = scst_changer_generic_parse(cmd);
break;
case TYPE_RAID:
rc = scst_raid_generic_parse(cmd);
break;
default:
PRINT_ERROR("Internal parse for type %d not supported",
cmd->dev->type);
goto out_hw_err;
}
if (rc != 0)
goto out_abn;
res = SCST_CMD_STATE_DEFAULT;
out:
TRACE_EXIT();
return res;
out_hw_err:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
out_abn:
res = scst_get_cmd_abnormal_done_state(cmd);
goto out;
}
/**
** Generic dev_done() support routines.
** Done via pointer on functions to avoid unneeded dereferences on
@@ -7556,7 +7611,10 @@ void scst_block_dev(struct scst_device *dev)
dev->virt_name);
}
/* dev_lock supposed to be held and BH disabled */
/*
* dev_lock supposed to be held and BH disabled. Returns true if cmd blocked,
* hence stop processing it and go to the next command.
*/
bool __scst_check_blocked_dev(struct scst_cmd *cmd)
{
int res = false;
@@ -8087,6 +8145,140 @@ char *scst_get_next_token_str(char **input_str)
}
EXPORT_SYMBOL_GPL(scst_get_next_token_str);
static bool scst_parse_unmap_descriptors(struct scst_cmd *cmd)
{
int res = false;
ssize_t length = 0;
uint8_t *address;
int i, cnt, offset, descriptor_len, total_len;
struct scst_data_descriptor *pd;
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(cmd->cmd_data_descriptors != NULL);
length = scst_get_buf_full(cmd, &address);
if (unlikely(length <= 0)) {
if (length == 0)
goto out_put;
else if (length == -ENOMEM)
scst_set_busy(cmd);
else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out_abn;
}
total_len = get_unaligned_be16(&cmd->cdb[7]);
offset = 8;
descriptor_len = get_unaligned_be16(&address[2]);
TRACE_DBG("total_len %d, descriptor_len %d", total_len, descriptor_len);
if (descriptor_len == 0)
goto out_put;
if (unlikely((descriptor_len > (total_len - 8)) ||
((descriptor_len % 16) != 0))) {
PRINT_ERROR("Bad descriptor length: %d < %d - 8",
descriptor_len, total_len);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
goto out_abn_put;
}
cnt = descriptor_len/16;
if (cnt == 0)
goto out_put;
pd = kzalloc(sizeof(*pd) * (cnt+1), GFP_KERNEL);
if (pd == NULL) {
PRINT_ERROR("Unable to kmalloc UNMAP %d descriptors", cnt+1);
scst_set_busy(cmd);
goto out_abn_put;
}
TRACE_DBG("cnt %d, pd %p", cnt, pd);
i = 0;
while ((offset - 8) < descriptor_len) {
struct scst_data_descriptor *d = &pd[i];
d->sdd_lba = get_unaligned_be64(&address[offset]);
offset += 8;
d->sdd_len = get_unaligned_be32(&address[offset]);
offset += 8;
TRACE_DBG("i %d, lba %lld, len %lld", i,
(long long )d->sdd_lba, (long long )d->sdd_len);
i++;
}
cmd->cmd_data_descriptors = pd;
cmd->cmd_data_descriptors_cnt = cnt;
out_put:
scst_put_buf_full(cmd, address);
out:
TRACE_EXIT_RES(res);
return res;
out_abn_put:
scst_put_buf_full(cmd, address);
out_abn:
scst_set_cmd_abnormal_done_state(cmd);
res = true;
goto out;
}
static void scst_free_unmap_descriptors(struct scst_cmd *cmd)
{
TRACE_ENTRY();
kfree(cmd->cmd_data_descriptors);
TRACE_EXIT();
return;
}
bool scst_parse_descriptors(struct scst_cmd *cmd)
{
bool res;
TRACE_ENTRY();
switch (cmd->cdb[0]) {
case UNMAP:
res = scst_parse_unmap_descriptors(cmd);
break;
default:
sBUG_ON(1);
res = false;
break;
}
TRACE_EXIT_RES(res);
return res;
}
static void scst_free_descriptors(struct scst_cmd *cmd)
{
TRACE_ENTRY();
switch (cmd->cdb[0]) {
case UNMAP:
scst_free_unmap_descriptors(cmd);
break;
default:
sBUG_ON(1);
break;
}
TRACE_EXIT();
return;
}
static void __init scst_scsi_op_list_init(void)
{
int i;
+3
View File
@@ -701,6 +701,9 @@ static inline void __scst_cmd_put(struct scst_cmd *cmd)
extern void scst_throttle_cmd(struct scst_cmd *cmd);
extern void scst_unthrottle_cmd(struct scst_cmd *cmd);
int scst_do_internal_parsing(struct scst_cmd *cmd);
bool scst_parse_descriptors(struct scst_cmd *cmd);
#ifdef CONFIG_SCST_DEBUG_TM
extern void tm_dbg_check_released_cmds(void);
extern int tm_dbg_check_cmd(struct scst_cmd *cmd);
+14 -7
View File
@@ -605,10 +605,10 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
}
scst_set_parse_time(cmd);
if (state == SCST_CMD_STATE_DEFAULT)
state = SCST_CMD_STATE_PREPARE_SPACE;
} else
state = scst_do_internal_parsing(cmd);
if (state == SCST_CMD_STATE_DEFAULT)
state = SCST_CMD_STATE_PREPARE_SPACE;
if (unlikely(state == SCST_CMD_STATE_PRE_XMIT_RESP) ||
@@ -1555,7 +1555,7 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
cmd->state = SCST_CMD_STATE_EXEC_CHECK_SN;
if ((cmd->tgtt->pre_exec == NULL) || unlikely(cmd->internal))
goto out;
goto out_descr;
TRACE_DBG("Calling pre_exec(%p)", cmd);
scst_set_cur_start(cmd);
@@ -1567,7 +1567,7 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
switch (rc) {
case SCST_PREPROCESS_STATUS_ERROR_SENSE_SET:
scst_set_cmd_abnormal_done_state(cmd);
break;
goto out;
case SCST_PREPROCESS_STATUS_ERROR_FATAL:
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
/* go through */
@@ -1575,13 +1575,20 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
scst_set_cmd_abnormal_done_state(cmd);
break;
goto out;
default:
sBUG();
break;
goto out;
}
}
out_descr:
if (unlikely(cmd->op_flags & SCST_DESCRIPTORS_BASED)) {
bool r = scst_parse_descriptors(cmd);
if (unlikely(r))
goto out;
}
out:
TRACE_EXIT_RES(res);
return res;