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:
Vladislav Bolkhovitin
2009-03-18 19:36:01 +00:00
parent 3fe295f5c1
commit 341f592a4a
8 changed files with 210 additions and 42 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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 \

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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 "

View File

@@ -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);