mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-19 06:22:22 +00:00
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:
+15
-1
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user