EXTENDED COPY support

Prepared with help from Sushma Gurram <Sushma.Gurram@sandisk.com>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6589 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2015-11-06 03:58:00 +00:00
parent 54cf21076a
commit 3fc775c75a
17 changed files with 4511 additions and 53 deletions
+71
View File
@@ -684,6 +684,7 @@ struct scst_acg;
struct scst_acg_dev;
struct scst_acn;
struct scst_aen;
struct scst_ext_copy_seg_descr;
struct scst_opcode_descriptor;
/*
@@ -1330,6 +1331,12 @@ struct scst_dev_type {
*/
unsigned pr_cmds_notifications:1;
/*
* Set if the Copy Manager can auto assing to devices of this
* template on their registration.
*/
unsigned auto_cm_assignment_possible:1;
/*
* Called to parse CDB from the cmd and initialize
* cmd->bufflen and cmd->data_direction (both - REQUIRED).
@@ -1420,6 +1427,26 @@ struct scst_dev_type {
*/
void (*on_free_cmd)(struct scst_cmd *cmd);
/*
* Called during EXTENDED COPY command processing to let dev hander
* try to remap blocks at first. Upon finish, the dev handler supposed
* to call scst_ext_copy_remap_done(). See description of this
* function for more details.
*
* In case of error, the dev handler should set the corresponding sense
* to cmd and then call scst_ext_copy_remap_done(cmd, NULL, 0).
*
* It is highly recommended that in the normal circumstances
* scst_ext_copy_remap_done() called from another thread context,
* because otherwise there will be recursion in the segments processing.
* Hopefully, this thread context switch is natural for such
* potentially long operation.
*
* OPTIONAL
*/
void (*ext_copy_remap)(struct scst_cmd *cmd,
struct scst_ext_copy_seg_descr *descr);
/*
* Called to notify dev handler that a ALUA state change is about to
* be started. Can be used to close open file handlers, which might
@@ -1938,6 +1965,14 @@ struct scst_session {
/* Used if scst_unregister_session() called in wait mode */
struct completion *shutdown_compl;
/*
* Keep list IDs for Extended Copy commands sent over this session.
* Protected by scst_cm_lock.
*/
struct list_head sess_cm_list_id_list;
struct delayed_work sess_cm_list_id_cleanup_work;
/* sysfs release completion */
struct completion *sess_kobj_release_cmpl;
@@ -2130,6 +2165,12 @@ struct scst_cmd {
/* Set if cmd is internally generated */
unsigned int internal:1;
/* Set if local events should be checked for internally generated cmd */
unsigned int internal_check_local_events:1;
/* Set if the blocking machinery should be bypassed for this cmd */
unsigned int bypass_blocking:1;
/* Set if the device was blocked by scst_check_blocked_dev() */
unsigned int unblock_dev:1;
@@ -2501,6 +2542,7 @@ struct scst_cmd {
uint64_t restart_waiting_time, rdy_to_xfer_time;
uint64_t pre_exec_time, exec_time, dev_done_time;
uint64_t xmit_time;
bool exec_time_counting;
#endif
#ifdef CONFIG_SCST_DEBUG_TM
@@ -3422,6 +3464,7 @@ extern const struct scst_opcode_descriptor scst_op_descr_stpg;
extern const struct scst_opcode_descriptor scst_op_descr_send_diagnostic;
extern const struct scst_opcode_descriptor scst_op_descr_inquiry;
extern const struct scst_opcode_descriptor scst_op_descr_extended_copy;
extern const struct scst_opcode_descriptor scst_op_descr_tur;
extern const struct scst_opcode_descriptor scst_op_descr_reserve6;
extern const struct scst_opcode_descriptor scst_op_descr_release6;
@@ -5602,4 +5645,32 @@ int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode,
int scst_pr_init_dev(struct scst_device *dev);
void scst_pr_clear_dev(struct scst_device *dev);
struct scst_ext_copy_data_descr {
uint64_t src_lba;
uint64_t dst_lba;
int data_len; /* in bytes */
};
struct scst_ext_copy_seg_descr {
#define SCST_EXT_COPY_SEG_DATA 0
#if 0 /* not implemented yet */
#define SCST_EXT_COPY_SEG_PR_REG 1
#define SCST_EXT_COPY_SEG_PR_MOVE 2
#endif
int type;
union {
struct {
struct scst_tgt_dev *src_tgt_dev;
struct scst_tgt_dev *dst_tgt_dev;
struct scst_ext_copy_data_descr data_descr;
};
};
/* Internal, don't touch! */
int tgt_descr_offs;
};
void scst_ext_copy_remap_done(struct scst_cmd *ec_cmd,
struct scst_ext_copy_data_descr *dds, int dds_cnt);
int scst_ext_copy_get_cur_seg_data_len(struct scst_cmd *ec_cmd);
#endif /* __SCST_H */
+22 -1
View File
@@ -230,7 +230,8 @@ enum scst_cdb_flags {
#endif
SCST_SERIALIZED = 0x10000,
SCST_STRICTLY_SERIALIZED = 0x20000|SCST_SERIALIZED,
SCST_DESCRIPTORS_BASED = 0x40000,
SCST_CAN_GEN_3PARTY_COMMANDS = 0x40000,
SCST_DESCRIPTORS_BASED = 0x80000,
SCST_SCSI_ATOMIC = 0x100000,
};
@@ -305,6 +306,8 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define scst_sense_set_target_pgs_failed HARDWARE_ERROR, 0x67, 0xA
/* ILLEGAL_REQUEST is 5 */
#define scst_sense_operation_in_progress ILLEGAL_REQUEST, 0x0, 0x16
#define scst_sense_parameter_list_length_invalid ILLEGAL_REQUEST, 0x1A, 0
#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0
#define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0
/* Don't use it directly, use scst_set_invalid_field_in_cdb() instead! */
@@ -314,6 +317,10 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0
#define scst_sense_parameter_value_invalid ILLEGAL_REQUEST, 0x26, 2
#define scst_sense_invalid_release ILLEGAL_REQUEST, 0x26, 4
#define scst_sense_too_many_target_descriptors ILLEGAL_REQUEST, 0x26, 6
#define scst_sense_unsupported_tgt_descr_type ILLEGAL_REQUEST, 0x26, 7
#define scst_sense_unsupported_seg_descr_type ILLEGAL_REQUEST, 0x26, 9
#define scst_sense_inline_data_length_exceeded ILLEGAL_REQUEST, 0x26, 0xB
#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0
#define scst_sense_invalid_message ILLEGAL_REQUEST, 0x49, 0
#define scst_sense_parameter_list_length_invalid ILLEGAL_REQUEST, 0x1A, 0
@@ -421,6 +428,14 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define WRITE_SAME_16 0x93
#endif
#ifndef EXTENDED_COPY
#define EXTENDED_COPY 0x83
#endif
#ifndef RECEIVE_COPY_RESULTS
#define RECEIVE_COPY_RESULTS 0x84
#endif
#ifndef SYNCHRONIZE_CACHE_16
#define SYNCHRONIZE_CACHE_16 0x91
#endif
@@ -590,6 +605,12 @@ enum {
#define SCSI_TRANSPORTID_PROTOCOLID_ISCSI 5
#define SCSI_TRANSPORTID_PROTOCOLID_SAS 6
/*
* SCST extension. Added, because there is no TransportID for Copy Manager
* defined anywhere in the SCSI standards.
*/
#define SCST_TRANSPORTID_PROTOCOLID_COPY_MGR 0xC
/**
* enum scst_tg_state - SCSI target port group asymmetric access state.
*
+33 -4
View File
@@ -71,10 +71,11 @@
#define UCMD_STATE_BUF_ALLOCING 2
#define UCMD_STATE_EXECING 3
#define UCMD_STATE_ON_FREEING 4
#define UCMD_STATE_ON_FREE_SKIPPED 5
#define UCMD_STATE_ON_CACHE_FREEING 6
#define UCMD_STATE_TM_RECEIVED_EXECING 7
#define UCMD_STATE_TM_DONE_EXECING 8
#define UCMD_STATE_ON_CACHE_FREEING 5
#define UCMD_STATE_EXT_COPY_REMAPPING 6
#define UCMD_STATE_ON_FREE_SKIPPED 7
#define UCMD_STATE_TM_RECEIVED_EXECING 8
#define UCMD_STATE_TM_DONE_EXECING 9
#define UCMD_STATE_ATTACH_SESS 0x20
#define UCMD_STATE_DETACH_SESS 0x21
@@ -96,6 +97,8 @@ struct scst_user_opt {
uint8_t d_sense;
uint8_t has_own_order_mgmt;
uint8_t ext_copy_remap_supported;
};
struct scst_user_dev_desc {
@@ -212,6 +215,19 @@ struct scst_user_tm {
uint8_t cmd_sn_set;
};
struct scst_user_ext_copy_data_descr {
aligned_u64 src_lba;
aligned_u64 dst_lba;
int32_t data_len; /* in bytes */
};
struct scst_user_ext_copy_remap {
aligned_u64 sess_h;
aligned_u64 src_sess_h;
aligned_u64 dst_sess_h;
struct scst_user_ext_copy_data_descr data_descr;
};
struct scst_user_get_cmd {
uint32_t cmd_h;
uint32_t subcode;
@@ -224,6 +240,7 @@ struct scst_user_get_cmd {
struct scst_user_scsi_on_free_cmd on_free_cmd;
struct scst_user_on_cached_mem_free on_cached_mem_free;
struct scst_user_tm tm_cmd;
struct scst_user_ext_copy_remap remap_cmd;
};
};
@@ -285,6 +302,15 @@ struct scst_user_scsi_cmd_reply_exec {
};
};
/* Be careful adding new members here, this structure is allocated on stack! */
struct scst_user_ext_copy_reply_remap {
aligned_u64 remap_descriptors;
uint16_t remap_descriptors_len;
uint8_t status;
uint8_t sense_len;
aligned_u64 psense_buffer;
};
/* Be careful adding new members here, this structure is allocated on stack! */
struct scst_user_reply_cmd {
uint32_t cmd_h;
@@ -294,6 +320,7 @@ struct scst_user_reply_cmd {
struct scst_user_scsi_cmd_reply_parse parse_reply;
struct scst_user_scsi_cmd_reply_alloc_mem alloc_reply;
struct scst_user_scsi_cmd_reply_exec exec_reply;
struct scst_user_ext_copy_reply_remap remap_reply;
};
};
@@ -362,5 +389,7 @@ struct scst_user_get_multi {
_IOWR('s', UCMD_STATE_TM_RECEIVED_EXECING, struct scst_user_tm)
#define SCST_USER_TASK_MGMT_DONE \
_IOWR('s', UCMD_STATE_TM_DONE_EXECING, struct scst_user_tm)
#define SCST_USER_EXT_COPY_REMAP \
_IOWR('s', UCMD_STATE_EXT_COPY_REMAPPING, struct scst_user_ext_copy_remap)
#endif /* __SCST_USER_H */
+1
View File
@@ -57,6 +57,7 @@ scst-y += scst_dlm.o
endif
scst-y += scst_tg.o
scst-y += scst_event.o
scst-y += scst_copy_mgr.o
obj-$(CONFIG_SCST) += scst.o dev_handlers/
obj-$(BUILD_DEV) += $(DEV_HANDLERS_DIR)/
+2
View File
@@ -92,6 +92,8 @@ EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
#EXTRA_CFLAGS += -DCONFIG_DEBUG_EXT_COPY_REMAP
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers \
Module.symvers Module.markers modules.order
+209 -12
View File
@@ -70,6 +70,7 @@ struct scst_user_dev {
unsigned int swp:1;
unsigned int d_sense:1;
unsigned int has_own_order_mgmt:1;
unsigned int ext_copy_remap_supported:1;
int (*generic_parse)(struct scst_cmd *cmd);
@@ -949,6 +950,37 @@ static int dev_user_exec(struct scst_cmd *cmd)
return res;
}
static void dev_user_ext_copy_remap(struct scst_cmd *cmd,
struct scst_ext_copy_seg_descr *seg)
{
struct scst_user_cmd *ucmd = cmd->dh_priv;
TRACE_ENTRY();
TRACE_DBG("Preparing EXT_COPY_REMAP for user space (ucmd=%p, h=%d, "
"seg %p)", ucmd, ucmd->h, seg);
ucmd->user_cmd_payload_len =
offsetof(struct scst_user_get_cmd, remap_cmd) +
sizeof(ucmd->user_cmd.remap_cmd);
ucmd->user_cmd.cmd_h = ucmd->h;
ucmd->user_cmd.subcode = SCST_USER_EXT_COPY_REMAP;
ucmd->user_cmd.remap_cmd.sess_h = (unsigned long)cmd->tgt_dev;
ucmd->user_cmd.remap_cmd.src_sess_h = (unsigned long)seg->src_tgt_dev;
ucmd->user_cmd.remap_cmd.dst_sess_h = (unsigned long)seg->dst_tgt_dev;
ucmd->user_cmd.remap_cmd.data_descr.src_lba = seg->data_descr.src_lba;
ucmd->user_cmd.remap_cmd.data_descr.dst_lba = seg->data_descr.dst_lba;
ucmd->user_cmd.remap_cmd.data_descr.data_len = seg->data_descr.data_len;
ucmd->state = UCMD_STATE_EXT_COPY_REMAPPING;
dev_user_add_to_ready(ucmd);
TRACE_EXIT();
return;
}
static void dev_user_free_sgv(struct scst_user_cmd *ucmd)
{
if (ucmd->sgv != NULL) {
@@ -1180,7 +1212,8 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd)
&dev->ready_cmd_list);
}
do_wake |= ((ucmd->state == UCMD_STATE_ON_CACHE_FREEING) ||
(ucmd->state == UCMD_STATE_ON_FREEING));
(ucmd->state == UCMD_STATE_ON_FREEING) ||
(ucmd->state == UCMD_STATE_EXT_COPY_REMAPPING));
}
if (do_wake) {
@@ -1444,6 +1477,150 @@ static int dev_user_process_reply_on_cache_free(struct scst_user_cmd *ucmd)
return res;
}
static int dev_user_process_reply_ext_copy_remap(struct scst_user_cmd *ucmd,
struct scst_user_reply_cmd *reply)
{
int res = 0, rc, count = 0, i, len;
struct scst_user_ext_copy_reply_remap *rreply = &reply->remap_reply;
struct scst_cmd *cmd = ucmd->cmd;
uint8_t *buf;
struct scst_user_ext_copy_data_descr *uleft;
struct scst_ext_copy_data_descr *left = NULL;
TRACE_ENTRY();
if (unlikely((rreply->status != 0) || (rreply->sense_len != 0)))
goto out_status;
if (rreply->remap_descriptors_len == 0) {
TRACE_DBG("No remap leftovers (ucmd %p, cmd %p)", ucmd, cmd);
goto out_done;
}
if (unlikely(rreply->remap_descriptors_len > PAGE_SIZE)) {
PRINT_ERROR("Too many leftover REMAP descriptors (len %d, ucmd %p, "
"cmd %p)", rreply->remap_descriptors_len, ucmd, cmd);
res = -EOVERFLOW;
goto out_hw_err;
}
buf = kzalloc(rreply->remap_descriptors_len, GFP_KERNEL);
if (unlikely(buf == NULL)) {
PRINT_ERROR("Unable to alloc leftover remap descriptors buf "
"(size %d)", rreply->remap_descriptors_len);
goto out_busy;
}
rc = copy_from_user(buf,
(void __user *)(unsigned long)rreply->remap_descriptors,
rreply->remap_descriptors_len);
if (unlikely(rc != 0)) {
PRINT_ERROR("Failed to copy %d leftover remap descriptors' "
"bytes", rc);
res = -EFAULT;
goto out_free_buf;
}
uleft = (struct scst_user_ext_copy_data_descr *)buf;
count = rreply->remap_descriptors_len / sizeof(*uleft);
if (unlikely((rreply->remap_descriptors_len % sizeof(*uleft)) != 0)) {
PRINT_ERROR("Invalid leftover remap descriptors (ucmd %p, "
"cmd %p, count %d)", ucmd, cmd, count);
res = -EINVAL;
goto out_hw_err_free_buf;
}
left = kmalloc(sizeof(*left) * count, GFP_KERNEL);
if (unlikely(left == NULL)) {
PRINT_ERROR("Unable to alloc leftover remap descriptors "
"(size %zd, count %d)", sizeof(*left) * count, count);
goto out_busy_free_buf;
}
TRACE_DBG("count %d", count);
len = 0;
for (i = 0; i < count; i++) {
TRACE_DBG("src_lba %lld, dst_lba %lld, data_len %d (len %d)",
(long long)uleft[i].src_lba, (long long)uleft[i].dst_lba,
uleft[i].data_len, len);
if (unlikely(uleft[i].data_len == 0)) {
PRINT_ERROR("Invalid data descr %d len %d (cmd %p)", i,
uleft[i].data_len, cmd);
res = -EINVAL;
goto out_hw_err_free_buf;
}
left[i].src_lba = uleft[i].src_lba;
left[i].dst_lba = uleft[i].dst_lba;
left[i].data_len = uleft[i].data_len;
len += uleft[i].data_len;
}
if (unlikely(len > scst_ext_copy_get_cur_seg_data_len(cmd))) {
PRINT_ERROR("Invalid data descr len %d (cmd %p, seg descr len %d)",
len, cmd, scst_ext_copy_get_cur_seg_data_len(cmd));
res = -EINVAL;
goto out_hw_err_free_buf;
}
out_free_buf:
kfree(buf);
out_done:
if (unlikely(res != 0)) {
kfree(left);
left = NULL;
count = 0;
}
scst_ext_copy_remap_done(cmd, left, count);
TRACE_EXIT_RES(res);
return res;
out_hw_err:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out_done;
out_hw_err_free_buf:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out_free_buf;
out_busy_free_buf:
scst_set_busy(cmd);
goto out_free_buf;
out_busy:
scst_set_busy(cmd);
goto out_done;
out_status:
TRACE_DBG("Remap finished with status %d (ucmd %p, cmd %p)",
rreply->status, ucmd, cmd);
if (rreply->sense_len != 0) {
int sense_len;
res = scst_alloc_sense(cmd, 0);
if (res != 0)
goto out_hw_err;
sense_len = min_t(int, cmd->sense_buflen, rreply->sense_len);
rc = copy_from_user(cmd->sense,
(void __user *)(unsigned long)rreply->psense_buffer,
sense_len);
if (rc != 0) {
PRINT_ERROR("Failed to copy %d sense's bytes", rc);
res = -EFAULT;
goto out_hw_err;
}
cmd->sense_valid_len = sense_len;
}
scst_set_cmd_error_status(cmd, rreply->status);
goto out_done;
}
static int dev_user_process_ws_reply(struct scst_user_cmd *ucmd,
struct scst_user_scsi_cmd_reply_exec *ereply)
{
@@ -1764,6 +1941,10 @@ unlock_process:
res = dev_user_process_reply_on_cache_free(ucmd);
break;
case UCMD_STATE_EXT_COPY_REMAPPING:
res = dev_user_process_reply_ext_copy_remap(ucmd, reply);
break;
case UCMD_STATE_TM_RECEIVED_EXECING:
case UCMD_STATE_TM_DONE_EXECING:
res = dev_user_process_reply_tm_exec(ucmd,
@@ -2460,6 +2641,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
break;
case UCMD_STATE_EXECING:
case UCMD_STATE_EXT_COPY_REMAPPING:
if (flags != NULL)
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock,
*flags);
@@ -2478,8 +2660,13 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
SCST_LOAD_SENSE(scst_sense_lun_not_supported));
}
ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT,
SCST_CONTEXT_THREAD);
if (state == UCMD_STATE_EXECING)
ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT,
SCST_CONTEXT_THREAD);
else {
sBUG_ON(state != UCMD_STATE_EXT_COPY_REMAPPING);
scst_ext_copy_remap_done(ucmd->cmd, NULL, 0);
}
/* !! At this point cmd and ucmd can be already freed !! */
if (flags != NULL)
@@ -3018,6 +3205,11 @@ static void dev_user_setup_functions(struct scst_user_dev *dev)
dev->devtype.dev_alloc_data_buf = dev_user_alloc_data_buf;
dev->devtype.dev_done = NULL;
if (dev->ext_copy_remap_supported)
dev->devtype.ext_copy_remap = dev_user_ext_copy_remap;
else
dev->devtype.ext_copy_remap = NULL;
if (dev->parse_type != SCST_USER_PARSE_CALL) {
switch (dev->devtype.type) {
case TYPE_DISK:
@@ -3471,9 +3663,10 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
TRACE_DBG("dev %s, parse_type %x, on_free_cmd_type %x, "
"memory_reuse_type %x, partial_transfers_type %x, "
"partial_len %d", dev->name, opt->parse_type,
opt->on_free_cmd_type, opt->memory_reuse_type,
opt->partial_transfers_type, opt->partial_len);
"partial_len %d, opt->ext_copy_remap_supported %d",
dev->name, opt->parse_type, opt->on_free_cmd_type,
opt->memory_reuse_type, opt->partial_transfers_type,
opt->partial_len, opt->ext_copy_remap_supported);
if (opt->parse_type > SCST_USER_MAX_PARSE_OPT ||
opt->on_free_cmd_type > SCST_USER_MAX_ON_FREE_CMD_OPT ||
@@ -3492,12 +3685,13 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
((opt->qerr == SCST_QERR_2_RESERVED) ||
(opt->qerr > SCST_QERR_3_ABORT_THIS_NEXUS_ONLY)) ||
(opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1) ||
(opt->d_sense > 1)) {
(opt->d_sense > 1) || (opt->ext_copy_remap_supported > 1)) {
PRINT_ERROR("Invalid SCSI option (tst %x, tmf_only %x, "
"queue_alg %x, qerr %x, swp %x, tas %x, d_sense %d, "
"has_own_order_mgmt %x)",
"has_own_order_mgmt %x, ext_copy_remap_supported %d)",
opt->tst, opt->tmf_only, opt->queue_alg, opt->qerr,
opt->swp, opt->tas, opt->d_sense, opt->has_own_order_mgmt);
opt->swp, opt->tas, opt->d_sense, opt->has_own_order_mgmt,
opt->ext_copy_remap_supported);
res = -EINVAL;
goto out;
}
@@ -3526,6 +3720,7 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
dev->tas = opt->tas;
dev->d_sense = opt->d_sense;
dev->has_own_order_mgmt = opt->has_own_order_mgmt;
dev->ext_copy_remap_supported = opt->ext_copy_remap_supported;
if (dev->sdev != NULL) {
dev->sdev->tst = opt->tst;
dev->sdev->tmf_only = opt->tmf_only;
@@ -3595,12 +3790,14 @@ static int dev_user_get_opt(struct file *file, void __user *arg)
opt.swp = dev->swp;
opt.d_sense = dev->d_sense;
opt.has_own_order_mgmt = dev->has_own_order_mgmt;
opt.ext_copy_remap_supported = dev->ext_copy_remap_supported;
TRACE_DBG("dev %s, parse_type %x, on_free_cmd_type %x, "
"memory_reuse_type %x, partial_transfers_type %x, "
"partial_len %d", dev->name, opt.parse_type,
opt.on_free_cmd_type, opt.memory_reuse_type,
opt.partial_transfers_type, opt.partial_len);
"partial_len %d, ext_copy_remap_supported %d", dev->name,
opt.parse_type, opt.on_free_cmd_type, opt.memory_reuse_type,
opt.partial_transfers_type, opt.partial_len,
opt.ext_copy_remap_supported);
rc = copy_to_user(arg, &opt, sizeof(opt));
if (unlikely(rc != 0)) {
+81
View File
@@ -357,6 +357,10 @@ static ssize_t vcdrom_del_device(const char *device_name);
static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev);
static uint64_t vdisk_gen_dev_id_num(const char *virt_dev_name);
#ifdef CONFIG_DEBUG_EXT_COPY_REMAP
static void vdev_ext_copy_remap(struct scst_cmd *cmd,
struct scst_ext_copy_seg_descr *descr);
#endif
static int vdisk_unmap_range(struct scst_cmd *cmd,
struct scst_vdisk_dev *virt_dev, uint64_t start_lba, uint32_t blocks);
@@ -677,6 +681,7 @@ static struct scst_dev_type vdisk_file_devtype = {
.threads_num = -1,
.parse_atomic = 1,
.dev_done_atomic = 1,
.auto_cm_assignment_possible = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
.attach_tgt = vdisk_attach_tgt,
@@ -686,6 +691,9 @@ static struct scst_dev_type vdisk_file_devtype = {
.exec = fileio_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
#ifdef CONFIG_DEBUG_EXT_COPY_REMAP
.ext_copy_remap = vdev_ext_copy_remap,
#endif
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)fileio_ops,
#ifdef CONFIG_SCST_PROC
@@ -734,6 +742,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
#ifdef CONFIG_SCST_PROC
.no_proc = 1,
#endif
.auto_cm_assignment_possible = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
.attach_tgt = vdisk_attach_tgt,
@@ -784,6 +793,7 @@ static struct scst_dev_type vdisk_null_devtype = {
#ifdef CONFIG_SCST_PROC
.no_proc = 1,
#endif
.auto_cm_assignment_possible = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
.attach_tgt = vdisk_attach_tgt,
@@ -827,6 +837,7 @@ static struct scst_dev_type vcdrom_devtype = {
.threads_num = -1,
.parse_atomic = 1,
.dev_done_atomic = 1,
.auto_cm_assignment_possible = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
.attach_tgt = vdisk_attach_tgt,
@@ -2757,6 +2768,7 @@ static vdisk_op_fn nullio_ops[256] = {
&scst_op_descr_write_same16, \
&scst_op_descr_unmap, \
&scst_op_descr_format_unit, \
&scst_op_descr_extended_copy, \
&scst_op_descr_cwr,
static const struct scst_opcode_descriptor *vdisk_opcode_descriptors[] = {
@@ -4256,6 +4268,7 @@ static int vdisk_inq(uint8_t *buf, struct scst_cmd *cmd,
if (virt_dev->expl_alua)
buf[5] |= SCST_INQ_TPGS_MODE_EXPLICIT;
}
buf[5] |= 8; /* 3PC */
buf[6] = 0x10; /* MultiP 1 */
buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */
@@ -7365,6 +7378,74 @@ static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
return;
}
#ifdef CONFIG_DEBUG_EXT_COPY_REMAP
static void vdev_ext_copy_remap(struct scst_cmd *cmd,
struct scst_ext_copy_seg_descr *seg)
{
struct scst_ext_copy_data_descr *d;
static int shift = 0;
static DEFINE_SPINLOCK(lock);
int s;
TRACE_ENTRY();
if (seg->data_descr.data_len <= 4096) {
/* No way to split */
goto out_done;
}
d = kzalloc(sizeof(*d)*2, GFP_KERNEL);
if (d == NULL)
goto out_busy;
spin_lock(&lock);
shift += 4096;
if (shift >= seg->data_descr.data_len) {
shift = 0;
s = 0;
} else
s = shift;
TRACE_DBG("cmd %p, seg %p, data_len %d, shift %d, s %d", cmd, seg,
seg->data_descr.data_len, shift, s);
spin_unlock(&lock);
if (s == 0)
goto out_free_done;
d[0].data_len = s;
d[0].src_lba = seg->data_descr.src_lba;
d[0].dst_lba = seg->data_descr.dst_lba;
d[1].data_len = seg->data_descr.data_len - s;
d[1].src_lba = seg->data_descr.src_lba + (s >> seg->src_tgt_dev->dev->block_shift);
d[1].dst_lba = seg->data_descr.dst_lba + (s >> seg->dst_tgt_dev->dev->block_shift);
scst_ext_copy_remap_done(cmd, d, 2);
out:
TRACE_EXIT();
return;
out_busy:
scst_set_busy(cmd);
out_free_done:
kfree(d);
out_done:
#if 1
scst_ext_copy_remap_done(cmd, &seg->data_descr, 1);
#else
scst_ext_copy_remap_done(cmd, NULL, 0);
#endif
goto out;
}
#endif
static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
{
enum { buf_size = 256 };
File diff suppressed because it is too large Load Diff
+4
View File
@@ -232,6 +232,10 @@ const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id)
transport_id[8], transport_id[9],
transport_id[10], transport_id[11]);
break;
case SCST_TRANSPORTID_PROTOCOLID_COPY_MGR:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"%s", &transport_id[2]);
break;
default:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"(Not known protocol ID %x)", transport_id[0] & 0x0f);
+51 -6
View File
@@ -172,6 +172,18 @@ const struct scst_opcode_descriptor scst_op_descr_inquiry = {
};
EXPORT_SYMBOL(scst_op_descr_inquiry);
const struct scst_opcode_descriptor scst_op_descr_extended_copy = {
.od_opcode = EXTENDED_COPY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { EXTENDED_COPY, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0xFF, 0xFF, 0xFF, 0xFF, 0,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_extended_copy);
const struct scst_opcode_descriptor scst_op_descr_tur = {
.od_opcode = TEST_UNIT_READY,
.od_support = 3, /* supported as in the standard */
@@ -468,6 +480,8 @@ static int get_cdb_info_write_same16(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_compare_and_write(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_ext_copy(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_apt(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_min(struct scst_cmd *cmd,
@@ -1256,16 +1270,18 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
.info_op_flags = SCST_WRITE_MEDIUM,
.info_len_off = 10, .info_len_len = 4,
.get_cdb_info = get_cdb_info_len_4},
{.ops = 0x83, .devkey = "OOOOOOOOOOOOOOOO",
{.ops = 0x83, .devkey = "O ", /* implemented only for disks */
.info_op_name = "EXTENDED COPY",
.info_data_direction = SCST_DATA_WRITE,
.info_op_flags = SCST_WRITE_MEDIUM,
.info_op_flags = SCST_WRITE_MEDIUM|SCST_CAN_GEN_3PARTY_COMMANDS|
SCST_LOCAL_CMD|SCST_DESCRIPTORS_BASED,
.info_len_off = 10, .info_len_len = 4,
.get_cdb_info = get_cdb_info_len_4},
{.ops = 0x84, .devkey = "OOOOOOOOOOOOOOOO",
.get_cdb_info = get_cdb_info_ext_copy},
{.ops = 0x84, .devkey = "O ", /* implemented only for disks */
.info_op_name = "RECEIVE COPY RESULT",
.info_data_direction = SCST_DATA_READ,
.info_op_flags = SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
.info_op_flags = SCST_FULLY_LOCAL_CMD|SCST_LOCAL_CMD|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
.info_len_off = 10, .info_len_len = 4,
.get_cdb_info = get_cdb_info_len_4},
{.ops = 0x85, .devkey = "O O O ",
@@ -6675,6 +6691,9 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask,
sess->tgt = tgt;
INIT_LIST_HEAD(&sess->init_deferred_cmd_list);
INIT_LIST_HEAD(&sess->init_deferred_mcmd_list);
INIT_LIST_HEAD(&sess->sess_cm_list_id_list);
INIT_DELAYED_WORK(&sess->sess_cm_list_id_cleanup_work,
(void (*)(struct work_struct *))sess_cm_list_id_cleanup_work_fn);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
INIT_DELAYED_WORK(&sess->hw_pending_work, scst_hw_pending_work_fn);
#else
@@ -11215,6 +11234,20 @@ static int get_cdb_info_compare_and_write(struct scst_cmd *cmd,
return scst_parse_wrprotect(cmd);
}
static int get_cdb_info_ext_copy(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
if (unlikely(cmd->cdb[1] != 0)) {
PRINT_WARNING("Not supported %s service action 0x%x",
scst_get_opcode_name(cmd), cmd->cdb[1]);
scst_set_invalid_field_in_cdb(cmd, 1,
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return 1;
}
return get_cdb_info_len_4(cmd, sdbops);
}
/**
* get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB.
*
@@ -12781,7 +12814,7 @@ bool __scst_check_blocked_dev(struct scst_cmd *cmd)
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(cmd->unblock_dev);
EXTRACHECKS_BUG_ON(cmd->internal);
EXTRACHECKS_BUG_ON(cmd->internal && cmd->cdb[0] != EXTENDED_COPY);
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
goto out;
@@ -13616,6 +13649,9 @@ int scst_parse_descriptors(struct scst_cmd *cmd)
case UNMAP:
res = scst_parse_unmap_descriptors(cmd);
break;
case EXTENDED_COPY:
res = scst_cm_parse_descriptors(cmd);
break;
default:
sBUG();
}
@@ -13632,6 +13668,9 @@ static void scst_free_descriptors(struct scst_cmd *cmd)
case UNMAP:
scst_free_unmap_descriptors(cmd);
break;
case EXTENDED_COPY:
scst_cm_free_descriptors(cmd);
break;
default:
sBUG();
break;
@@ -15112,6 +15151,12 @@ void scst_set_pre_exec_time(struct scst_cmd *cmd)
TRACE_DBG("cmd %p: pre_exec_time %lld", cmd, cmd->pre_exec_time);
}
void scst_set_exec_start(struct scst_cmd *cmd)
{
cmd->exec_time_counting = true;
scst_set_cur_start(cmd);
}
void scst_set_exec_time(struct scst_cmd *cmd)
{
cmd->exec_time += scst_get_usec() - cmd->curr_start;
+28
View File
@@ -1469,6 +1469,10 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
list_add_tail(&dev->dev_list_entry, &scst_dev_list);
res = scst_cm_on_dev_register(dev);
if (res != 0)
goto out_unreg;
mutex_unlock(&scst_mutex);
scst_resume_activity();
@@ -1480,6 +1484,12 @@ out:
TRACE_EXIT_RES(res);
return res;
out_unreg:
dev->dev_unregistering = 1;
list_del(&dev->dev_list_entry);
scst_assign_dev_handler(dev, &scst_null_devtype);
goto out_pr_clear_dev;
#ifndef CONFIG_SCST_PROC
out_lock_pr_clear_dev:
mutex_lock(&scst_mutex);
@@ -1532,6 +1542,8 @@ void scst_unregister_virtual_device(int id)
dev->dev_unregistering = 1;
scst_cm_on_dev_unregister(dev);
list_del_init(&dev->dev_list_entry);
scst_pr_clear_dev(dev);
@@ -2659,6 +2671,15 @@ static int __init init_scst(void)
goto out_thread_free;
#endif
res = scst_cm_init();
if (res != 0)
#ifdef CONFIG_SCST_PROC
goto out_proc_cleanup;
#else
goto out_thread_free;
#endif
PRINT_INFO("SCST version %s loaded successfully (max mem for "
"commands %dMB, per device %dMB)", SCST_VERSION_STRING,
scst_max_cmd_mem, scst_max_dev_cmd_mem);
@@ -2669,6 +2690,11 @@ out:
TRACE_EXIT_RES(res);
return res;
#ifdef CONFIG_SCST_PROC
out_proc_cleanup:
scst_proc_cleanup_module();
#endif
out_thread_free:
scst_stop_global_threads();
@@ -2751,6 +2777,8 @@ static void __exit exit_scst(void)
/* ToDo: unregister_cpu_notifier() */
scst_cm_exit();
#ifdef CONFIG_SCST_PROC
scst_proc_cleanup_module();
#endif
+66 -2
View File
@@ -713,6 +713,10 @@ void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev,
void scst_block_dev(struct scst_device *dev);
void scst_unblock_dev(struct scst_device *dev);
bool scst_do_check_blocked_dev(struct scst_cmd *cmd);
bool __scst_check_blocked_dev(struct scst_cmd *cmd);
void __scst_check_unblock_dev(struct scst_cmd *cmd);
void scst_check_unblock_dev(struct scst_cmd *cmd);
int scst_ext_block_dev(struct scst_device *dev, bool sync,
ext_blocker_done_fn_t done_fn, const uint8_t *priv, int priv_len);
@@ -720,8 +724,6 @@ void scst_ext_unblock_dev(struct scst_device *dev, bool stpg);
void __scst_ext_blocking_done(struct scst_device *dev);
void scst_ext_blocking_done(struct scst_device *dev);
bool __scst_check_blocked_dev(struct scst_cmd *cmd);
/*
* Increases global SCST ref counters which prevent from entering into suspended
* activities stage, so protects from any global management operations.
@@ -842,6 +844,66 @@ static inline bool scst_lba1_inside_lba2(int64_t lba1,
return res;
}
#ifndef CONFIG_SCST_PROC
int scst_cm_on_dev_register(struct scst_device *dev);
void scst_cm_on_dev_unregister(struct scst_device *dev);
int scst_cm_parse_descriptors(struct scst_cmd *cmd);
void scst_cm_free_descriptors(struct scst_cmd *cmd);
int scst_cm_ext_copy_exec(struct scst_cmd *cmd);
int scst_cm_rcv_copy_res_exec(struct scst_cmd *cmd);
void sess_cm_list_id_cleanup_work_fn(struct delayed_work *work);
void scst_cm_free_pending_list_ids(struct scst_session *sess);
bool scst_cm_check_block_all_devs(struct scst_cmd *cmd);
void scst_cm_abort_ec_cmd(struct scst_cmd *ec_cmd);
bool scst_cm_ec_cmd_overlap(struct scst_cmd *ec_cmd, struct scst_cmd *cmd);
int scst_cm_init(void);
void scst_cm_exit(void);
#else /* #ifndef CONFIG_SCST_PROC */
static inline int scst_cm_on_dev_register(struct scst_device *dev) { return 0; }
static inline void scst_cm_on_dev_unregister(struct scst_device *dev) {}
static inline int scst_cm_parse_descriptors(struct scst_cmd *cmd)
{
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
scst_set_cmd_abnormal_done_state(cmd);
return -1;
}
static inline void scst_cm_free_descriptors(struct scst_cmd *cmd) {}
static inline int scst_cm_ext_copy_exec(struct scst_cmd *cmd)
{
return SCST_EXEC_NOT_COMPLETED;
}
static inline int scst_cm_rcv_copy_res_exec(struct scst_cmd *cmd)
{
return SCST_EXEC_NOT_COMPLETED;
}
static inline void sess_cm_list_id_cleanup_work_fn(struct work_struct *work) {}
static inline void scst_cm_free_pending_list_ids(struct scst_session *sess) {}
static inline bool scst_cm_check_block_all_devs(struct scst_cmd *cmd) { return false; }
static inline void scst_cm_abort_ec_cmd(struct scst_cmd *ec_cmd) {}
static inline bool scst_cm_ec_cmd_overlap(struct scst_cmd *ec_cmd, struct scst_cmd *cmd)
{
return false;
}
static inline int scst_cm_init(void) { return 0; }
static inline void scst_cm_exit(void) {}
#endif /* #ifndef CONFIG_SCST_PROC */
#ifdef CONFIG_SCST_DEBUG_TM
extern void tm_dbg_check_released_cmds(void);
extern int tm_dbg_check_cmd(struct scst_cmd *cmd);
@@ -901,6 +963,7 @@ void scst_set_alloc_buf_time(struct scst_cmd *cmd);
void scst_set_restart_waiting_time(struct scst_cmd *cmd);
void scst_set_rdy_to_xfer_time(struct scst_cmd *cmd);
void scst_set_pre_exec_time(struct scst_cmd *cmd);
void scst_set_exec_start(struct scst_cmd *cmd);
void scst_set_exec_time(struct scst_cmd *cmd);
void scst_set_dev_done_time(struct scst_cmd *cmd);
void scst_set_xmit_time(struct scst_cmd *cmd);
@@ -915,6 +978,7 @@ static inline void scst_set_alloc_buf_time(struct scst_cmd *cmd) {}
static inline void scst_set_restart_waiting_time(struct scst_cmd *cmd) {}
static inline void scst_set_rdy_to_xfer_time(struct scst_cmd *cmd) {}
static inline void scst_set_pre_exec_time(struct scst_cmd *cmd) {}
static inline void scst_set_exec_start(struct scst_cmd *cmd) {}
static inline void scst_set_exec_time(struct scst_cmd *cmd) {}
static inline void scst_set_dev_done_time(struct scst_cmd *cmd) {}
static inline void scst_set_xmit_time(struct scst_cmd *cmd) {}
+46 -6
View File
@@ -162,6 +162,9 @@ static bool scst_cmd_overlap_cwr(struct scst_cmd *cwr_cmd, struct scst_cmd *cmd)
res = scst_unmap_overlap(cmd, cwr_cmd->lba,
cwr_cmd->data_len);
break;
case EXTENDED_COPY:
res = scst_cm_ec_cmd_overlap(cmd, cwr_cmd);
break;
default:
res = false;
break;
@@ -430,12 +433,21 @@ static bool scst_check_blocked_dev(struct scst_cmd *cmd)
TRACE_ENTRY();
if (unlikely(cmd->internal)) {
if (unlikely((cmd->op_flags & SCST_CAN_GEN_3PARTY_COMMANDS) != 0)) {
EXTRACHECKS_BUG_ON(cmd->cdb[0] != EXTENDED_COPY);
res = scst_cm_check_block_all_devs(cmd);
goto out;
}
if (unlikely(cmd->internal || cmd->bypass_blocking)) {
/*
* The original command can already block the device and must
* hold reference to it, so internal command should always pass.
*/
sBUG_ON(dev->on_dev_cmd_count == 0);
/* Copy Manager can send internal INQUIRYs, so don't BUG on them */
sBUG_ON((dev->on_dev_cmd_count == 0) && (cmd->cdb[0] != INQUIRY));
res = false;
goto out;
}
@@ -2087,7 +2099,17 @@ 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))
if (unlikely(cmd->internal)) {
if (cmd->dh_data_buf_alloced && cmd->tgt_i_data_buf_alloced &&
(scst_cmd_get_data_direction(cmd) & SCST_DATA_WRITE)) {
TRACE_DBG("Internal WRITE cmd %p with DH alloced data",
cmd);
scst_copy_sg(cmd, SCST_SG_COPY_FROM_TARGET);
}
goto out_descr;
}
if (cmd->tgtt->pre_exec == NULL)
goto out_descr;
TRACE_DBG("Calling pre_exec(%p)", cmd);
@@ -3161,7 +3183,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
TRACE_ENTRY();
if (unlikely(cmd->internal)) {
if (unlikely(cmd->internal && !cmd->internal_check_local_events)) {
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, aborting internal "
"cmd %p", cmd);
@@ -3399,7 +3421,7 @@ static int scst_do_real_exec(struct scst_cmd *cmd)
if (devt->exec) {
TRACE_DBG("Calling dev handler %s exec(%p)",
devt->name, cmd);
scst_set_cur_start(cmd);
scst_set_exec_start(cmd);
res = devt->exec(cmd);
TRACE_DBG("Dev handler %s exec() returned %d",
devt->name, res);
@@ -3425,7 +3447,7 @@ static int scst_do_real_exec(struct scst_cmd *cmd)
goto out_error;
}
scst_set_cur_start(cmd);
scst_set_exec_start(cmd);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
rc = scst_exec_req(scsi_dev, cmd->cdb, cmd->cdb_len,
@@ -3519,6 +3541,8 @@ static scst_local_exec_fn scst_local_fns[256] = {
[REPORT_LUNS] = scst_report_luns_local,
[REQUEST_SENSE] = scst_request_sense_local,
[COMPARE_AND_WRITE] = scst_cmp_wr_local,
[EXTENDED_COPY] = scst_cm_ext_copy_exec,
[RECEIVE_COPY_RESULTS] = scst_cm_rcv_copy_res_exec,
[MAINTENANCE_IN] = scst_maintenance_in,
};
@@ -5785,6 +5809,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
TRACE_ENTRY();
/* Fantom EC commands must not leak here */
sBUG_ON((cmd->cdb[0] == EXTENDED_COPY) && cmd->internal);
/*
* Help Coverity recognize that mcmd != NULL if
* call_dev_task_mgmt_fn_received == true.
@@ -5834,6 +5861,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
*/
smp_mb__after_set_bit();
if (cmd->cdb[0] == EXTENDED_COPY)
scst_cm_abort_ec_cmd(cmd);
if (cmd->tgt_dev == NULL) {
spin_lock_irqsave(&scst_init_lock, flags);
scst_init_poll_cnt++;
@@ -6911,6 +6941,16 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
tgt_done:
scst_call_task_mgmt_affected_cmds_done(mcmd);
switch (mcmd->fn) {
case SCST_LUN_RESET:
case SCST_TARGET_RESET:
case SCST_NEXUS_LOSS_SESS:
case SCST_NEXUS_LOSS:
case SCST_UNREG_SESS_TM:
scst_cm_free_pending_list_ids(sess);
break;
}
res = scst_set_mcmd_next_state(mcmd);
TRACE_EXIT_RES(res);
+1
View File
@@ -49,6 +49,7 @@ CFLAGS += $(LOCAL_CFLAGS)
#CFLAGS += -DDEBUG_TM_IGNORE
#CFLAGS += -DDEBUG_TM_IGNORE -DDEBUG_TM_FN_IGNORE
#CFLAGS += -DDEBUG_TM_IGNORE_ALL
CFLAGS += -DDEBUG_EXT_COPY_REMAP
all: $(PROGS)
+151 -22
View File
@@ -69,11 +69,31 @@ static int open_dev_fd(struct vdisk_dev *dev)
return res;
}
static inline void set_cmd_error_status(struct scst_user_scsi_cmd_reply_exec *reply,
static void set_resp_data_len(struct vdisk_cmd *vcmd, int32_t resp_data_len)
{
struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
TRACE_ENTRY();
if (vcmd->may_need_to_free_pbuf && (resp_data_len == 0)) {
struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
free((void *)(unsigned long)cmd->pbuf);
cmd->pbuf = 0;
reply->pbuf = 0;
}
reply->resp_data_len = resp_data_len;
TRACE_EXIT();
return;
}
static inline void set_cmd_error_status(struct vdisk_cmd *vcmd,
int status)
{
struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
reply->status = status;
reply->resp_data_len = 0;
set_resp_data_len(vcmd, 0);
return;
}
@@ -108,7 +128,7 @@ void set_cmd_error(struct vdisk_cmd *vcmd, int key, int asc, int ascq)
EXTRACHECKS_BUG_ON(vcmd->cmd->subcode != SCST_USER_EXEC);
set_cmd_error_status(reply, SAM_STAT_CHECK_CONDITION);
set_cmd_error_status(vcmd, SAM_STAT_CHECK_CONDITION);
reply->sense_len = set_sense(vcmd->sense, sizeof(vcmd->sense), key,
asc, ascq);
reply->psense_buffer = (unsigned long)vcmd->sense;
@@ -117,11 +137,11 @@ void set_cmd_error(struct vdisk_cmd *vcmd, int key, int asc, int ascq)
return;
}
void set_busy(struct scst_user_scsi_cmd_reply_exec *reply)
void set_busy(struct vdisk_cmd *vcmd)
{
TRACE_ENTRY();
set_cmd_error_status(reply, SAM_STAT_TASK_SET_FULL);
set_cmd_error_status(vcmd, SAM_STAT_TASK_SET_FULL);
TRACE_MGMT_DBG("%s", "Sending QUEUE_FULL status");
TRACE_EXIT();
@@ -212,6 +232,9 @@ static int do_exec(struct vdisk_cmd *vcmd)
TRACE_ENTRY();
/* Must be reinitialized each time to avoid crash on stale value */
vcmd->may_need_to_free_pbuf = 0;
switch(cmd->queue_type) {
case SCST_CMD_QUEUE_ORDERED:
TRACE(TRACE_ORDER, "ORDERED cmd_h %d", vcmd->cmd->cmd_h);
@@ -251,6 +274,7 @@ static int do_exec(struct vdisk_cmd *vcmd)
else
#endif
cmd->pbuf = (unsigned long)dev->alloc_fn(cmd->alloc_len);
vcmd->may_need_to_free_pbuf = 1;
TRACE_MEM("Buf %"PRIx64" alloced, len %d", cmd->pbuf,
cmd->alloc_len);
reply->pbuf = cmd->pbuf;
@@ -258,7 +282,7 @@ static int do_exec(struct vdisk_cmd *vcmd)
TRACE(TRACE_OUT_OF_MEM, "Unable to allocate buffer "
"(len %d)", cmd->alloc_len);
#ifndef DEBUG_NOMEM
set_busy(reply);
set_busy(vcmd);
#endif
goto out;
}
@@ -524,6 +548,49 @@ static int do_on_free_cmd(struct vdisk_cmd *vcmd)
return res;
}
#ifdef DEBUG_EXT_COPY_REMAP
static int do_ext_copy_remap(struct vdisk_cmd *vcmd)
{
struct scst_user_get_cmd *cmd = vcmd->cmd;
struct scst_user_ext_copy_remap *rcmd = &cmd->remap_cmd;
struct scst_user_reply_cmd *reply = vcmd->reply;
struct scst_user_ext_copy_reply_remap *rreply = &reply->remap_reply;
static struct scst_user_ext_copy_data_descr d[1];
int res = 0;
TRACE_ENTRY();
TRACE_DBG("Ext copy remap cmd %d", cmd->cmd_h);
memset(reply, 0, sizeof(*reply));
reply->cmd_h = cmd->cmd_h;
reply->subcode = cmd->subcode;
memset(rreply, 0, sizeof(*rreply));
/* It's only a debug code, so it's OK to use static descr */
memset(d, 0, sizeof(d));
d[0].data_len = rcmd->data_descr.data_len;
d[0].src_lba = rcmd->data_descr.src_lba;
d[0].dst_lba = rcmd->data_descr.dst_lba;
#if 1
rreply->remap_descriptors = (unsigned long)d;
rreply->remap_descriptors_len = sizeof(d);
#else
rreply->status = SAM_STAT_CHECK_CONDITION;
rreply->sense_len = set_sense(vcmd->sense, sizeof(vcmd->sense),
SCST_LOAD_SENSE(scst_sense_data_protect));
rreply->psense_buffer = (unsigned long)vcmd->sense;
#endif
TRACE_EXIT_RES(res);
return res;
}
#endif
static int do_tm(struct vdisk_cmd *vcmd, int done)
{
struct scst_user_get_cmd *cmd = vcmd->cmd;
@@ -668,6 +735,12 @@ static int process_cmd(struct vdisk_cmd *vcmd)
res = do_on_free_cmd(vcmd);
break;
#ifdef DEBUG_EXT_COPY_REMAP
case SCST_USER_EXT_COPY_REMAP:
res = do_ext_copy_remap(vcmd);
break;
#endif
case SCST_USER_TASK_MGMT_RECEIVED:
res = do_tm(vcmd, 0);
break;
@@ -704,7 +777,14 @@ void *main_loop(void *arg)
struct vdisk_dev *dev = (struct vdisk_dev *)arg;
struct scst_user_get_cmd cmd;
struct scst_user_reply_cmd reply;
struct vdisk_cmd vcmd = { -1, &cmd, dev, &reply, {0}};
struct vdisk_cmd vcmd = {
.fd = -1,
.cmd = &cmd,
.dev = dev,
.may_need_to_free_pbuf = 0,
.reply = &reply,
.sense = {0}
};
int scst_usr_fd = dev->scst_usr_fd;
struct pollfd pl;
#define MULTI_CMDS_CNT 2
@@ -746,6 +826,7 @@ void *main_loop(void *arg)
}
}
#endif
if (use_multi) {
TRACE_DBG("preplies %p (first: %p), replies_cnt %d, "
"replies_done %d, cmds_cnt %d", (void *)multi.multi_cmd.preplies,
@@ -906,11 +987,13 @@ static void exec_inquiry(struct vdisk_cmd *vcmd)
uint64_t dev_id_num = gen_dev_id_num(dev);
if (0 == cmd->cdb[2]) { /* supported vital product data pages */
buf[3] = 3;
buf[3] = 5;
buf[4] = 0x0; /* this page */
buf[5] = 0x80; /* unit serial number */
buf[6] = 0x83; /* device identification */
resp_len = buf[3] + 4;
buf[7] = 0xB0; /* block limits */
buf[8] = 0xB1; /* block device characteristics */
resp_len = buf[3] + 6;
} else if (0x80 == cmd->cdb[2]) { /* unit serial number */
int usn_len = strlen(dev->usn);
buf[1] = 0x80;
@@ -957,6 +1040,55 @@ static void exec_inquiry(struct vdisk_cmd *vcmd)
buf[2] = (resp_len >> 8) & 0xFF;
buf[3] = resp_len & 0xFF;
resp_len += 4;
} else if (0xB0 == cmd->cdb[2]) {
/* Block Limits */
int max_transfer;
buf[1] = 0xB0;
buf[3] = 0x3C;
buf[5] = 0xFF; /* No MAXIMUM COMPARE AND WRITE LENGTH limit */
/* Optimal transfer granuality is PAGE_SIZE */
max_transfer = max((int)(4096/dev->block_size), (int)1);
buf[6] = (max_transfer >> 8) & 0xff;
buf[7] = max_transfer & 0xff;
/*
* Max transfer len is min of sg limit and 8M, but we
* don't have access to them here, so let's use 1M.
*/
max_transfer = 1*1024*1024;
buf[8] = (max_transfer >> 24) & 0xff;
buf[9] = (max_transfer >> 16) & 0xff;
buf[10] = (max_transfer >> 8) & 0xff;
buf[11] = max_transfer & 0xff;
/*
* Let's have optimal transfer len 512KB. Better to not
* set it at all, because we don't have such limit,
* but some initiators may not understand that (?).
* From other side, too big transfers are not optimal,
* because SGV cache supports only <4M buffers.
*/
max_transfer = min((int)max_transfer, (int)(512*1024 / dev->block_size));
buf[12] = (max_transfer >> 24) & 0xff;
buf[13] = (max_transfer >> 16) & 0xff;
buf[14] = (max_transfer >> 8) & 0xff;
buf[15] = max_transfer & 0xff;
resp_len = buf[3] + 4;
} else if (0xB1 == cmd->cdb[2]) {
int r;
/* Block Device Characteristics */
buf[1] = 0xB1;
buf[3] = 0x3C;
#if 0
if (virt_dev->rotational) {
#endif
/* 15K RPM */
r = 0x3A98;
#if 0
} else
r = 1;
#endif
buf[4] = (r >> 8) & 0xff;
buf[5] = r & 0xff;
resp_len = buf[3] + 4;
} else {
TRACE_DBG("INQUIRY: Unsupported EVPD page %x",
cmd->cdb[2]);
@@ -1000,7 +1132,7 @@ static void exec_inquiry(struct vdisk_cmd *vcmd)
memcpy(address, buf, length);
if (length < reply->resp_data_len)
reply->resp_data_len = length;
set_resp_data_len(vcmd, length);
out:
TRACE_EXIT();
@@ -1024,7 +1156,7 @@ static void exec_request_sense(struct vdisk_cmd *vcmd)
memcpy(address, b, length);
if (length < reply->resp_data_len)
reply->resp_data_len = length;
set_resp_data_len(vcmd, length);
TRACE_EXIT();
return;
@@ -1265,7 +1397,7 @@ static void exec_mode_sense(struct vdisk_cmd *vcmd)
memcpy(address, buf, offset);
if (offset < reply->resp_data_len)
reply->resp_data_len = offset;
set_resp_data_len(vcmd, offset);
out:
TRACE_EXIT();
@@ -1396,7 +1528,7 @@ static void exec_read_capacity(struct vdisk_cmd *vcmd)
memcpy(address, buffer, length);
if (length < reply->resp_data_len)
reply->resp_data_len = length;
set_resp_data_len(vcmd, length);
TRACE_EXIT();
return;
@@ -1455,7 +1587,7 @@ static void exec_read_capacity16(struct vdisk_cmd *vcmd)
memcpy(address, buffer, length);
if (length < reply->resp_data_len)
reply->resp_data_len = length;
set_resp_data_len(vcmd, length);
TRACE_EXIT();
return;
@@ -1534,7 +1666,7 @@ static void exec_read_toc(struct vdisk_cmd *vcmd)
memcpy(address, buffer, off);
if (off < reply->resp_data_len)
reply->resp_data_len = off;
set_resp_data_len(vcmd, off);
out:
TRACE_EXIT();
@@ -1577,7 +1709,6 @@ static void exec_read(struct vdisk_cmd *vcmd, loff_t loff)
{
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;
int length = cmd->bufflen;
uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
int fd = vcmd->fd;
@@ -1606,7 +1737,7 @@ static void exec_read(struct vdisk_cmd *vcmd, loff_t loff)
PRINT_ERROR("read() returned %"PRId64" from %d (errno %d)",
(uint64_t)err, length, errno);
if (err == -EAGAIN)
set_busy(reply);
set_busy(vcmd);
else {
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_read_error));
@@ -1614,7 +1745,7 @@ static void exec_read(struct vdisk_cmd *vcmd, loff_t loff)
goto out;
}
reply->resp_data_len = cmd->bufflen;
set_resp_data_len(vcmd, cmd->bufflen);
out:
TRACE_EXIT();
@@ -1625,7 +1756,6 @@ static void exec_write(struct vdisk_cmd *vcmd, loff_t loff)
{
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;
loff_t err;
int length = cmd->bufflen;
uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
@@ -1658,7 +1788,7 @@ restart:
PRINT_ERROR("write() returned %"PRId64" from %d (errno %d, "
"cmd_h %x)", err, length, errno, vcmd->cmd->cmd_h);
if (err == -EAGAIN)
set_busy(reply);
set_busy(vcmd);
else {
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_write_error));
@@ -1687,7 +1817,6 @@ static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff)
{
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;
loff_t err;
int64_t length = cmd->bufflen;
uint8_t *address = (uint8_t *)(unsigned long)cmd->pbuf;
@@ -1740,7 +1869,7 @@ static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff)
PRINT_ERROR("read() returned %"PRId64" from %"PRId64" "
"(errno %d)", (uint64_t)err, len_mem, errno);
if (err == -EAGAIN)
set_busy(reply);
set_busy(vcmd);
else {
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_read_error));
+1
View File
@@ -97,6 +97,7 @@ struct vdisk_cmd
int fd;
struct scst_user_get_cmd *cmd;
struct vdisk_dev *dev;
unsigned int may_need_to_free_pbuf:1;
struct scst_user_reply_cmd *reply;
uint8_t sense[SCST_SENSE_BUFFERSIZE];
};
+3
View File
@@ -394,6 +394,9 @@ int start(int argc, char **argv)
desc.opt.queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
desc.opt.qerr = SCST_QERR_0_ALL_RESUME;
desc.opt.d_sense = SCST_D_SENSE_0_FIXED_SENSE;
#ifdef DEBUG_EXT_COPY_REMAP
desc.opt.ext_copy_remap_supported = 1;
#endif
res = ioctl(devs[i].scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
if (res != 0) {