mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-07 08:36:45 +00:00
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:
@@ -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 */
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user