mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-20 14:16:31 +00:00
Support for variable lenght CDB added
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@702 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+40
-9
@@ -899,7 +899,7 @@ struct scst_dev_type {
|
||||
/*
|
||||
* Name of the dev handler. Must be unique. MUST HAVE.
|
||||
*
|
||||
* It's SCST_MAX_NAME + few more bytes to match scst_user requirements.
|
||||
* It's SCST_MAX_NAME + few more bytes to match scst_user expectations.
|
||||
*/
|
||||
char name[SCST_MAX_NAME + 10];
|
||||
|
||||
@@ -1235,7 +1235,9 @@ struct scst_cmd {
|
||||
|
||||
/* CDB and its len */
|
||||
uint8_t cdb[SCST_MAX_CDB_SIZE];
|
||||
int cdb_len;
|
||||
unsigned short cdb_len;
|
||||
unsigned short ext_cdb_len;
|
||||
uint8_t *ext_cdb;
|
||||
|
||||
enum scst_cdb_flags op_flags;
|
||||
const char *op_name;
|
||||
@@ -1831,8 +1833,8 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type);
|
||||
* same sess. Returns the command on success or NULL otherwise
|
||||
*/
|
||||
struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
|
||||
const uint8_t *lun, int lun_len,
|
||||
const uint8_t *cdb, int cdb_len, int atomic);
|
||||
const uint8_t *lun, int lun_len, const uint8_t *cdb,
|
||||
int cdb_len, int atomic);
|
||||
|
||||
/*
|
||||
* Notifies SCST that the driver finished its part of the command
|
||||
@@ -1964,11 +1966,8 @@ static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
|
||||
}
|
||||
|
||||
/*
|
||||
* Provides various CDB info
|
||||
* Parameters:
|
||||
* cdb_p - pointer to CDB
|
||||
* dev_type - SCSI device type
|
||||
* op_flags, direction, transfer_len, cdb_len, op_name - the result (output)
|
||||
* Provides various info about command's CDB.
|
||||
*
|
||||
* Returns: 0 on success, <0 if command is unknown, >0 if command is invalid.
|
||||
*/
|
||||
int scst_get_cdb_info(struct scst_cmd *cmd);
|
||||
@@ -2146,6 +2145,38 @@ static inline enum scst_exec_context scst_estimate_context_direct(void)
|
||||
return __scst_estimate_context(1);
|
||||
}
|
||||
|
||||
/* Returns cmd's CDB */
|
||||
static inline const uint8_t *scst_cmd_get_cdb(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->cdb;
|
||||
}
|
||||
|
||||
/* Returns cmd's CDB length */
|
||||
static inline int scst_cmd_get_cdb_len(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->cdb_len;
|
||||
}
|
||||
|
||||
/* Returns cmd's extended CDB */
|
||||
static inline const uint8_t *scst_cmd_get_ext_cdb(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->ext_cdb;
|
||||
}
|
||||
|
||||
/* Returns cmd's extended CDB length */
|
||||
static inline int scst_cmd_get_ext_cdb_len(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->ext_cdb_len;
|
||||
}
|
||||
|
||||
/* Sets cmd's extended CDB and its length */
|
||||
static inline void scst_cmd_set_ext_cdb(struct scst_cmd *cmd,
|
||||
uint8_t *ext_cdb, unsigned int ext_cdb_len)
|
||||
{
|
||||
cmd->ext_cdb = ext_cdb;
|
||||
cmd->ext_cdb_len = ext_cdb_len;
|
||||
}
|
||||
|
||||
/* Returns cmd's session */
|
||||
static inline struct scst_session *scst_cmd_get_session(struct scst_cmd *cmd)
|
||||
{
|
||||
|
||||
@@ -107,7 +107,8 @@ struct scst_user_scsi_cmd_parse {
|
||||
aligned_u64 sess_h;
|
||||
|
||||
uint8_t cdb[SCST_MAX_CDB_SIZE];
|
||||
int32_t cdb_len;
|
||||
uint16_t cdb_len;
|
||||
uint16_t ext_cdb_len;
|
||||
|
||||
int32_t timeout;
|
||||
int32_t bufflen;
|
||||
@@ -126,7 +127,8 @@ struct scst_user_scsi_cmd_alloc_mem {
|
||||
aligned_u64 sess_h;
|
||||
|
||||
uint8_t cdb[SCST_MAX_CDB_SIZE];
|
||||
int32_t cdb_len;
|
||||
uint16_t cdb_len;
|
||||
uint16_t ext_cdb_len;
|
||||
|
||||
int32_t alloc_len;
|
||||
|
||||
@@ -140,7 +142,8 @@ struct scst_user_scsi_cmd_exec {
|
||||
aligned_u64 sess_h;
|
||||
|
||||
uint8_t cdb[SCST_MAX_CDB_SIZE];
|
||||
int32_t cdb_len;
|
||||
uint16_t cdb_len;
|
||||
uint16_t ext_cdb_len;
|
||||
|
||||
int32_t data_len;
|
||||
int32_t bufflen;
|
||||
@@ -233,6 +236,11 @@ struct scst_user_reply_cmd {
|
||||
};
|
||||
};
|
||||
|
||||
struct scst_user_get_ext_cdb {
|
||||
uint32_t cmd_h;
|
||||
aligned_u64 ext_cdb_buffer;
|
||||
};
|
||||
|
||||
#define SCST_USER_REGISTER_DEVICE _IOW('u', 1, struct scst_user_dev_desc)
|
||||
#define SCST_USER_UNREGISTER_DEVICE _IO('u', 2)
|
||||
#define SCST_USER_SET_OPTIONS _IOW('u', 3, struct scst_user_opt)
|
||||
@@ -241,6 +249,7 @@ struct scst_user_reply_cmd {
|
||||
#define SCST_USER_REPLY_CMD _IOW('u', 6, struct scst_user_reply_cmd)
|
||||
#define SCST_USER_FLUSH_CACHE _IO('u', 7)
|
||||
#define SCST_USER_DEVICE_CAPACITY_CHANGED _IO('u', 8)
|
||||
#define SCST_USER_GET_EXTENDED_CDB _IOWR('u', 9, struct scst_user_get_ext_cdb)
|
||||
|
||||
/* Values for scst_user_get_cmd.subcode */
|
||||
#define SCST_USER_ATTACH_SESS \
|
||||
|
||||
@@ -643,9 +643,9 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
|
||||
ucmd->user_cmd.cmd_h = ucmd->h;
|
||||
ucmd->user_cmd.subcode = SCST_USER_ALLOC_MEM;
|
||||
ucmd->user_cmd.alloc_cmd.sess_h = (unsigned long)cmd->tgt_dev;
|
||||
memcpy(ucmd->user_cmd.alloc_cmd.cdb, cmd->cdb,
|
||||
min(sizeof(ucmd->user_cmd.alloc_cmd.cdb), sizeof(cmd->cdb)));
|
||||
memcpy(ucmd->user_cmd.alloc_cmd.cdb, cmd->cdb, cmd->cdb_len);
|
||||
ucmd->user_cmd.alloc_cmd.cdb_len = cmd->cdb_len;
|
||||
ucmd->user_cmd.alloc_cmd.ext_cdb_len = cmd->ext_cdb_len;
|
||||
ucmd->user_cmd.alloc_cmd.alloc_len = ucmd->buff_cached ?
|
||||
(cmd->sg_cnt << PAGE_SHIFT) : cmd->bufflen;
|
||||
ucmd->user_cmd.alloc_cmd.queue_type = cmd->queue_type;
|
||||
@@ -766,10 +766,9 @@ static int dev_user_parse(struct scst_cmd *cmd)
|
||||
ucmd->user_cmd.cmd_h = ucmd->h;
|
||||
ucmd->user_cmd.subcode = SCST_USER_PARSE;
|
||||
ucmd->user_cmd.parse_cmd.sess_h = (unsigned long)cmd->tgt_dev;
|
||||
memcpy(ucmd->user_cmd.parse_cmd.cdb, cmd->cdb,
|
||||
min(sizeof(ucmd->user_cmd.parse_cmd.cdb),
|
||||
sizeof(cmd->cdb)));
|
||||
memcpy(ucmd->user_cmd.parse_cmd.cdb, cmd->cdb, cmd->cdb_len);
|
||||
ucmd->user_cmd.parse_cmd.cdb_len = cmd->cdb_len;
|
||||
ucmd->user_cmd.parse_cmd.ext_cdb_len = cmd->ext_cdb_len;
|
||||
ucmd->user_cmd.parse_cmd.timeout = cmd->timeout / HZ;
|
||||
ucmd->user_cmd.parse_cmd.bufflen = cmd->bufflen;
|
||||
ucmd->user_cmd.parse_cmd.queue_type = cmd->queue_type;
|
||||
@@ -882,16 +881,17 @@ static int dev_user_exec(struct scst_cmd *cmd)
|
||||
if (cmd->data_direction == SCST_DATA_WRITE)
|
||||
dev_user_flush_dcache(ucmd);
|
||||
|
||||
BUILD_BUG_ON(sizeof(ucmd->user_cmd.exec_cmd.cdb) != sizeof(cmd->cdb));
|
||||
|
||||
ucmd->user_cmd_payload_len =
|
||||
offsetof(struct scst_user_get_cmd, exec_cmd) +
|
||||
sizeof(ucmd->user_cmd.exec_cmd);
|
||||
ucmd->user_cmd.cmd_h = ucmd->h;
|
||||
ucmd->user_cmd.subcode = SCST_USER_EXEC;
|
||||
ucmd->user_cmd.exec_cmd.sess_h = (unsigned long)cmd->tgt_dev;
|
||||
memcpy(ucmd->user_cmd.exec_cmd.cdb, cmd->cdb,
|
||||
min(sizeof(ucmd->user_cmd.exec_cmd.cdb),
|
||||
sizeof(cmd->cdb)));
|
||||
memcpy(ucmd->user_cmd.exec_cmd.cdb, cmd->cdb, cmd->cdb_len);
|
||||
ucmd->user_cmd.exec_cmd.cdb_len = cmd->cdb_len;
|
||||
ucmd->user_cmd.exec_cmd.ext_cdb_len = cmd->ext_cdb_len;
|
||||
ucmd->user_cmd.exec_cmd.bufflen = cmd->bufflen;
|
||||
ucmd->user_cmd.exec_cmd.data_len = cmd->data_len;
|
||||
ucmd->user_cmd.exec_cmd.pbuf = ucmd->ubuff;
|
||||
@@ -1545,6 +1545,90 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int dev_user_get_ext_cdb(struct file *file, void __user *arg)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_user_dev *dev;
|
||||
struct scst_user_cmd *ucmd;
|
||||
struct scst_cmd *cmd;
|
||||
struct scst_user_get_ext_cdb get;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&dev_priv_mutex);
|
||||
dev = (struct scst_user_dev *)file->private_data;
|
||||
res = dev_user_check_reg(dev);
|
||||
if (unlikely(res != 0)) {
|
||||
mutex_unlock(&dev_priv_mutex);
|
||||
goto out;
|
||||
}
|
||||
down_read(&dev->dev_rwsem);
|
||||
mutex_unlock(&dev_priv_mutex);
|
||||
|
||||
res = copy_from_user(&get, arg, sizeof(get));
|
||||
if (unlikely(res < 0))
|
||||
goto out_up;
|
||||
|
||||
TRACE_MGMT_DBG("Get ext cdb for dev %s", dev->name);
|
||||
|
||||
TRACE_BUFFER("Get ext cdb", &get, sizeof(get));
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
|
||||
ucmd = __ucmd_find_hash(dev, get.cmd_h);
|
||||
if (unlikely(ucmd == NULL)) {
|
||||
TRACE_MGMT_DBG("cmd_h %d not found", get.cmd_h);
|
||||
res = -ESRCH;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (unlikely(ucmd_get_check(ucmd))) {
|
||||
TRACE_MGMT_DBG("Found being destroyed cmd_h %d", get.cmd_h);
|
||||
res = -ESRCH;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if ((ucmd->cmd != NULL) && (ucmd->state <= UCMD_STATE_EXECING) &&
|
||||
(ucmd->sent_to_user || ucmd->background_exec)) {
|
||||
cmd = ucmd->cmd;
|
||||
scst_cmd_get(cmd);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("Invalid ucmd state %d for cmd_h %d",
|
||||
ucmd->state, get.cmd_h);
|
||||
res = -EINVAL;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
|
||||
if (cmd == NULL)
|
||||
goto out_put;
|
||||
|
||||
if (cmd->ext_cdb == NULL)
|
||||
goto out_cmd_put;
|
||||
|
||||
TRACE_BUFFER("EXT CDB", cmd->ext_cdb, cmd->ext_cdb_len);
|
||||
res = copy_to_user((void __user *)(unsigned long)get.ext_cdb_buffer,
|
||||
cmd->ext_cdb, cmd->ext_cdb_len);
|
||||
|
||||
out_cmd_put:
|
||||
scst_cmd_put(cmd);
|
||||
|
||||
out_put:
|
||||
ucmd_put(ucmd);
|
||||
|
||||
out_up:
|
||||
up_read(&dev->dev_rwsem);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
static int dev_user_process_scst_commands(struct scst_user_dev *dev)
|
||||
__releases(&dev->cmd_lists.cmd_list_lock)
|
||||
__acquires(&dev->cmd_lists.cmd_list_lock)
|
||||
@@ -1814,6 +1898,11 @@ static long dev_user_ioctl(struct file *file, unsigned int cmd,
|
||||
res = dev_user_reply_cmd(file, (void __user *)arg);
|
||||
break;
|
||||
|
||||
case SCST_USER_GET_EXTENDED_CDB:
|
||||
TRACE_DBG("%s", "GET_EXTENDED_CDB");
|
||||
res = dev_user_get_ext_cdb(file, (void __user *)arg);
|
||||
break;
|
||||
|
||||
case SCST_USER_REGISTER_DEVICE:
|
||||
{
|
||||
struct scst_user_dev_desc *dev_desc;
|
||||
|
||||
+3
-2
@@ -84,8 +84,9 @@ struct sgv_pool {
|
||||
struct sgv_pool_acc acc;
|
||||
struct sgv_pool_cache_acc cache_acc[SGV_POOL_ELEMENTS];
|
||||
|
||||
char cache_names[SGV_POOL_ELEMENTS][25];
|
||||
char name[25];
|
||||
/* SCST_MAX_NAME + few more bytes to match scst_user expectations */
|
||||
char cache_names[SGV_POOL_ELEMENTS][SCST_MAX_NAME + 10];
|
||||
char name[SCST_MAX_NAME + 10];
|
||||
struct list_head sgv_pool_list_entry;
|
||||
};
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
|
||||
}
|
||||
|
||||
if (unlikely(cmd->cdb_len == 0)) {
|
||||
PRINT_ERROR("Wrong CDB len %d, finishing cmd", 0);
|
||||
PRINT_ERROR("%s", "Wrong CDB len, finishing cmd");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
scst_set_cmd_abnormal_done_state(cmd);
|
||||
@@ -370,7 +370,7 @@ static int scst_pre_parse(struct scst_cmd *cmd)
|
||||
cmd->data_direction = cmd->expected_data_direction;
|
||||
|
||||
cmd->bufflen = cmd->expected_transfer_len;
|
||||
/* Restore (likely) lost CDB length */
|
||||
/* Restore (possibly) lost CDB length */
|
||||
cmd->cdb_len = scst_get_cdb_len(cmd->cdb);
|
||||
if (cmd->cdb_len == -1) {
|
||||
PRINT_ERROR("Unable to get CDB length for "
|
||||
|
||||
Reference in New Issue
Block a user