mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +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:
@@ -84,13 +84,32 @@ static inline u32 cmnd_read_size(struct iscsi_cmnd *cmnd)
|
||||
struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
|
||||
|
||||
if (hdr->flags & ISCSI_CMD_READ) {
|
||||
struct iscsi_rlength_ahdr *ahdr =
|
||||
(struct iscsi_rlength_ahdr *)cmnd->pdu.ahs;
|
||||
struct iscsi_ahs_hdr *ahdr;
|
||||
|
||||
if (!(hdr->flags & ISCSI_CMD_WRITE))
|
||||
return be32_to_cpu(hdr->data_length);
|
||||
if (ahdr && ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH)
|
||||
return be32_to_cpu(ahdr->read_length);
|
||||
|
||||
ahdr = (struct iscsi_ahs_hdr *)cmnd->pdu.ahs;
|
||||
if (ahdr != NULL) {
|
||||
uint8_t *p = (uint8_t *)ahdr;
|
||||
int size = 0;
|
||||
do {
|
||||
int s;
|
||||
|
||||
ahdr = (struct iscsi_ahs_hdr *)p;
|
||||
|
||||
if (ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH) {
|
||||
struct iscsi_rlength_ahdr *rh =
|
||||
(struct iscsi_rlength_ahdr *)ahdr;
|
||||
return be32_to_cpu(rh->read_length);
|
||||
}
|
||||
|
||||
s = 3 + be16_to_cpu(ahdr->ahslength);
|
||||
s = (s + 3) & -4;
|
||||
size += s;
|
||||
p += s;
|
||||
} while (size < cmnd->pdu.ahssize);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1280,6 +1299,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
|
||||
struct scst_cmd *scst_cmd;
|
||||
scst_data_direction dir;
|
||||
struct iscsi_ahs_hdr *ahdr;
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -1343,6 +1363,29 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
/* cmd_sn is already in CPU format converted in check_cmd_sn() */
|
||||
scst_cmd_set_tgt_sn(scst_cmd, req_hdr->cmd_sn);
|
||||
|
||||
ahdr = (struct iscsi_ahs_hdr *)req->pdu.ahs;
|
||||
if (ahdr != NULL) {
|
||||
uint8_t *p = (uint8_t *)ahdr;
|
||||
int size = 0;
|
||||
do {
|
||||
int s;
|
||||
|
||||
ahdr = (struct iscsi_ahs_hdr *)p;
|
||||
|
||||
if (ahdr->ahstype == ISCSI_AHSTYPE_CDB) {
|
||||
struct iscsi_cdb_ahdr *eca =
|
||||
(struct iscsi_cdb_ahdr *)ahdr;
|
||||
scst_cmd_set_ext_cdb(scst_cmd, eca->cdb,
|
||||
be16_to_cpu(ahdr->ahslength) - 1);
|
||||
break;
|
||||
}
|
||||
s = 3 + be16_to_cpu(ahdr->ahslength);
|
||||
s = (s + 3) & -4;
|
||||
size += s;
|
||||
p += s;
|
||||
} while (size < req->pdu.ahssize);
|
||||
}
|
||||
|
||||
TRACE_DBG("START Command (tag %d, queue_type %d)",
|
||||
req_hdr->itt, scst_cmd->queue_type);
|
||||
req->scst_state = ISCSI_CMD_STATE_RX_CMD;
|
||||
|
||||
@@ -798,20 +798,17 @@ static int recv(struct iscsi_conn *conn)
|
||||
iscsi_conn_init_read(conn,
|
||||
(void __force __user *)&conn->rpadding, psz);
|
||||
conn->read_state = RX_PADDING;
|
||||
} else if (ddigest) {
|
||||
} else if (ddigest)
|
||||
conn->read_state = RX_INIT_DDIGEST;
|
||||
goto init_ddigest;
|
||||
} else {
|
||||
else
|
||||
conn->read_state = RX_END;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RX_PADDING:
|
||||
res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END);
|
||||
if (res <= 0 || conn->read_state != RX_INIT_DDIGEST)
|
||||
break;
|
||||
case RX_INIT_DDIGEST:
|
||||
init_ddigest:
|
||||
iscsi_conn_init_read(conn,
|
||||
(void __force __user *)&cmnd->ddigest, sizeof(u32));
|
||||
conn->read_state = RX_DDIGEST;
|
||||
@@ -1511,19 +1508,16 @@ int iscsi_send(struct iscsi_conn *conn)
|
||||
cmnd->pdu.datasize;
|
||||
if (cmnd->conn->write_size != 0)
|
||||
conn->write_state = TX_PADDING;
|
||||
else if (ddigest) {
|
||||
else if (ddigest)
|
||||
conn->write_state = TX_INIT_DDIGEST;
|
||||
goto init_ddigest;
|
||||
} else {
|
||||
else
|
||||
conn->write_state = TX_END;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TX_PADDING:
|
||||
res = tx_padding(cmnd, ddigest ? TX_INIT_DDIGEST : TX_END);
|
||||
if (res <= 0 || conn->write_state != TX_INIT_DDIGEST)
|
||||
break;
|
||||
case TX_INIT_DDIGEST:
|
||||
init_ddigest:
|
||||
cmnd->conn->write_size = sizeof(u32);
|
||||
conn->write_state = TX_DDIGEST;
|
||||
case TX_DDIGEST:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -555,8 +555,9 @@ static int do_alloc_mem(struct vdisk_cmd *vcmd)
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MEM("Alloc mem (cmd %d, sess_h %"PRIx64", cdb_len %d, "
|
||||
"alloc_len %d, queue_type %d, data_direction %d)", cmd->cmd_h,
|
||||
cmd->alloc_cmd.sess_h, cmd->alloc_cmd.cdb_len,
|
||||
"ext_cdb_len %d, alloc_len %d, queue_type %d, data_direction "
|
||||
"%d)", cmd->cmd_h, cmd->alloc_cmd.sess_h,
|
||||
cmd->alloc_cmd.cdb_len, cmd->alloc_cmd.ext_cdb_len,
|
||||
cmd->alloc_cmd.alloc_len, cmd->alloc_cmd.queue_type,
|
||||
cmd->alloc_cmd.data_direction);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user