From 3b57904da6adfdce5c5e1330ccbfcef4762dfcef Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Mon, 7 May 2012 22:39:54 +0000 Subject: [PATCH] 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 --- scst/include/scst.h | 16 ++- scst/include/scst_const.h | 3 +- scst/src/dev_handlers/scst_vdisk.c | 53 +------- scst/src/scst_lib.c | 198 ++++++++++++++++++++++++++++- scst/src/scst_priv.h | 3 + scst/src/scst_targ.c | 21 ++- 6 files changed, 236 insertions(+), 58 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 49532fae7..154c1b674 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -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 */ diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index 76d1fdfa2..f914496a1 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.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, }; /************************************************************* diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index cf2dc751a..da107dd26 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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(); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 5d9b87a18..a87e757fe 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index a4ce96537..7b68aaae0 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -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); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index a4a836955..a055f80e0 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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;