Bidirectional data transfers added

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@744 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2009-04-03 17:49:26 +00:00
parent f8eebf8dd8
commit e62b39196b
11 changed files with 464 additions and 236 deletions
+15 -1
View File
@@ -2,7 +2,7 @@
USER SPACE INTERFACE DESCRIPTION.
Version 1.0.0
Version 1.0.2
I. Description.
@@ -341,6 +341,7 @@ struct scst_user_scsi_cmd_parse
uint32_t timeout;
int32_t bufflen;
int32_t in_bufflen;
uint8_t queue_type;
uint8_t data_direction;
@@ -367,6 +368,9 @@ where:
- bufflen - command's buffer length
- in_bufflen - for bidirectional commands command's IN, i.e. from
initiator to target, buffer length
- queue_type - SCSI task attribute (queue type)
- data_direction - command's data flow direction, one of SCST_DATA_*
@@ -536,6 +540,9 @@ struct scst_user_scsi_cmd_exec
uint8_t partial;
uint32_t timeout;
aligned_u64 p_in_buf;
int32_t in_bufflen;
uint32_t sn;
uint32_t parent_cmd_h;
@@ -580,6 +587,13 @@ where:
- timeout - CDB execution timeout
- p_in_buf - for bidirectional commands pointer on command's IN, i.e. from
initiator to target, data buffer or 0 for SCSI commands without data
transfer
- in_bufflen - for bidirectional commands command's IN, i.e. from
initiator to target, buffer length
- sn - command's SN, which might be used for task management
- parent_cmd_h - has the same unique value for all partial data
+151 -123
View File
@@ -55,9 +55,6 @@ DECLARE_WAIT_QUEUE_HEAD(iscsi_wr_waitQ);
static struct page *dummy_page;
static struct scatterlist dummy_sg;
static uint8_t sense_fixed_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
static uint8_t sense_descr_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
struct iscsi_thread_t {
struct task_struct *thr;
struct list_head threads_list_entry;
@@ -81,7 +78,7 @@ static inline u32 cmnd_write_size(struct iscsi_cmnd *cmnd)
return 0;
}
static inline u32 cmnd_read_size(struct iscsi_cmnd *cmnd)
static inline int cmnd_read_size(struct iscsi_cmnd *cmnd)
{
struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
@@ -112,6 +109,7 @@ static inline u32 cmnd_read_size(struct iscsi_cmnd *cmnd)
p += s;
} while (size < cmnd->pdu.ahssize);
}
return -1;
}
return 0;
}
@@ -611,13 +609,13 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
struct iscsi_cmnd *rsp;
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
struct iscsi_data_in_hdr *rsp_hdr;
u32 pdusize, expsize, scsisize, size, offset, sn;
u32 pdusize, expsize, size, offset, sn;
LIST_HEAD(send);
TRACE_DBG("req %p", req);
pdusize = req->conn->session->sess_param.max_xmit_data_length;
expsize = cmnd_read_size(req);
expsize = req->read_size;
size = min(expsize, (u32)req->bufflen);
offset = 0;
sn = 0;
@@ -640,21 +638,26 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
TRACE_DBG("offset %d, size %d", offset, size);
rsp->pdu.datasize = size;
if (send_status) {
int scsisize;
TRACE_DBG("status %x", status);
rsp_hdr->flags =
ISCSI_FLG_FINAL | ISCSI_FLG_STATUS;
EXTRACHECKS_BUG_ON((cmnd_hdr(req)->flags & ISCSI_CMD_WRITE) != 0);
rsp_hdr->flags = ISCSI_FLG_FINAL | ISCSI_FLG_STATUS;
rsp_hdr->cmd_status = status;
scsisize = req->bufflen;
if (scsisize < expsize) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
size = expsize - scsisize;
} else if (scsisize > expsize) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW;
size = scsisize - expsize;
} else
size = 0;
rsp_hdr->residual_count = cpu_to_be32(size);
}
scsisize = req->bufflen;
if (scsisize < expsize) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
size = expsize - scsisize;
} else if (scsisize > expsize) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW;
size = scsisize - expsize;
} else
size = 0;
rsp_hdr->residual_count = cpu_to_be32(size);
list_add_tail(&rsp->write_list_entry, &send);
break;
}
@@ -969,11 +972,71 @@ static void cmnd_prepare_get_rejected_cmd_data(struct iscsi_cmnd *cmnd)
return;
}
static void iscsi_set_resid(struct iscsi_cmnd *req, struct iscsi_cmnd *rsp,
bool data_used)
{
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
struct iscsi_scsi_rsp_hdr *rsp_hdr;
int resid, resp_len, in_resp_len;
if ((req_hdr->flags & ISCSI_CMD_READ) &&
(req_hdr->flags & ISCSI_CMD_WRITE)) {
rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
if (data_used) {
resp_len = req->bufflen;
if (req->scst_cmd != NULL)
in_resp_len = scst_cmd_get_in_bufflen(req->scst_cmd);
else
in_resp_len = 0;
} else {
resp_len = 0;
in_resp_len = 0;
}
resid = be32_to_cpu(req_hdr->data_length) - in_resp_len;
if (resid > 0) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count = cpu_to_be32(resid);
} else if (resid < 0) {
resid = -resid;
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW;
rsp_hdr->residual_count = cpu_to_be32(resid);
}
resid = req->read_size - resp_len;
if (resid > 0) {
rsp_hdr->flags |= ISCSI_FLG_BIRESIDUAL_UNDERFLOW;
rsp_hdr->bi_residual_count = cpu_to_be32(resid);
} else if (resid < 0) {
resid = -resid;
rsp_hdr->flags |= ISCSI_FLG_BIRESIDUAL_OVERFLOW;
rsp_hdr->bi_residual_count = cpu_to_be32(resid);
}
} else {
if (data_used)
resp_len = req->bufflen;
else
resp_len = 0;
resid = req->read_size - resp_len;
if (resid > 0) {
rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count = cpu_to_be32(resid);
} else if (resid < 0) {
rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
resid = -resid;
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW;
rsp_hdr->residual_count = cpu_to_be32(resid);
}
}
return;
}
static void cmnd_reject_scsi_cmd(struct iscsi_cmnd *req)
{
struct iscsi_cmnd *rsp;
struct iscsi_scsi_rsp_hdr *rsp_hdr;
u32 size;
TRACE_DBG("%p", req);
@@ -987,25 +1050,9 @@ static void cmnd_reject_scsi_cmd(struct iscsi_cmnd *req)
goto out_reject;
}
rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
sBUG_ON(cmnd_opcode(rsp) != ISCSI_OP_SCSI_RSP);
size = cmnd_write_size(req);
if (size) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count = cpu_to_be32(size);
}
size = cmnd_read_size(req);
if (size) {
if (cmnd_hdr(req)->flags & ISCSI_CMD_WRITE) {
rsp_hdr->flags |= ISCSI_FLG_BIRESIDUAL_UNDERFLOW;
rsp_hdr->bi_residual_count = cpu_to_be32(size);
} else {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count = cpu_to_be32(size);
}
}
iscsi_set_resid(req, rsp, false);
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
ISCSI_INIT_WRITE_WAKE);
@@ -1152,11 +1199,6 @@ static int iscsi_pre_exec(struct scst_cmd *scst_cmd)
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
if (scst_cmd_get_data_direction(scst_cmd) == SCST_DATA_READ) {
EXTRACHECKS_BUG_ON(!list_empty(&req->rx_ddigest_cmd_list));
goto out;
}
/* If data digest isn't used this list will be empty */
list_for_each_entry_safe(c, t, &req->rx_ddigest_cmd_list,
rx_ddigest_cmd_list_entry) {
@@ -1326,17 +1368,44 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
scst_cmd_set_tag(scst_cmd, req_hdr->itt);
scst_cmd_set_tgt_priv(scst_cmd, req);
if (req_hdr->flags & ISCSI_CMD_READ) {
if ((req_hdr->flags & ISCSI_CMD_READ) &&
(req_hdr->flags & ISCSI_CMD_WRITE)) {
int sz = cmnd_read_size(req);
if (unlikely(sz < 0)) {
PRINT_ERROR("%s", "BIDI data transfer, but initiator "
"not supplied Bidirectional Read Expected Data "
"Transfer Length AHS");
scst_set_cmd_error(scst_cmd,
SCST_LOAD_SENSE(scst_sense_parameter_value_invalid));
/*
* scst_cmd_init_done() will handle commands with
* set status as preliminary completed
*/
} else {
req->read_size = sz;
dir = SCST_DATA_BIDI;
scst_cmd_set_expected(scst_cmd, dir, sz);
scst_cmd_set_expected_in_transfer_len(scst_cmd,
be32_to_cpu(req_hdr->data_length));
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
#endif
}
} else if (req_hdr->flags & ISCSI_CMD_READ) {
req->read_size = be32_to_cpu(req_hdr->data_length);
dir = SCST_DATA_READ;
scst_cmd_set_expected(scst_cmd, dir, req->read_size);
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
#endif
} else if (req_hdr->flags & ISCSI_CMD_WRITE)
} else if (req_hdr->flags & ISCSI_CMD_WRITE) {
dir = SCST_DATA_WRITE;
else
scst_cmd_set_expected(scst_cmd, dir,
be32_to_cpu(req_hdr->data_length));
} else {
dir = SCST_DATA_NONE;
scst_cmd_set_expected(scst_cmd, dir,
be32_to_cpu(req_hdr->data_length));
scst_cmd_set_expected(scst_cmd, dir, 0);
}
switch (req_hdr->flags & ISCSI_CMD_ATTR_MASK) {
case ISCSI_CMD_SIMPLE:
@@ -1410,35 +1479,40 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
}
dir = scst_cmd_get_data_direction(scst_cmd);
if (dir != SCST_DATA_WRITE) {
if (unlikely(!(req_hdr->flags & ISCSI_CMD_FINAL) ||
req->pdu.datasize)) {
PRINT_ERROR("Unexpected unsolicited data (ITT %x "
"CDB %x", cmnd_itt(req), req_hdr->scb[0]);
if (scst_get_cmd_dev_d_sense(scst_cmd))
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
sense_descr_unexpected_unsolicited_data,
sizeof(sense_descr_unexpected_unsolicited_data));
else
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
sense_fixed_unexpected_unsolicited_data,
sizeof(sense_fixed_unexpected_unsolicited_data));
cmnd_reject_scsi_cmd(req);
goto out;
}
}
if (dir == SCST_DATA_WRITE) {
if (dir & SCST_DATA_WRITE) {
req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL);
req->r2t_length = be32_to_cpu(req_hdr->data_length) -
req->pdu.datasize;
if (req->r2t_length > 0)
req->data_waiting = 1;
} else {
if (unlikely(!(req_hdr->flags & ISCSI_CMD_FINAL) ||
req->pdu.datasize)) {
PRINT_ERROR("Unexpected unsolicited data (ITT %x "
"CDB %x", cmnd_itt(req), req_hdr->scb[0]);
scst_set_cmd_error(scst_cmd,
SCST_LOAD_SENSE(iscsi_sense_unexpected_unsolicited_data));
if (scst_cmd_get_sense_buffer(scst_cmd) != NULL)
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
scst_cmd_get_sense_buffer(scst_cmd),
scst_cmd_get_sense_buffer_len(scst_cmd));
else
create_status_rsp(req, SAM_STAT_BUSY, NULL, 0);
cmnd_reject_scsi_cmd(req);
goto out;
}
}
req->target_task_tag = get_next_ttt(conn);
req->sg = scst_cmd_get_sg(scst_cmd);
req->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd);
req->bufflen = scst_cmd_get_bufflen(scst_cmd);
if (dir != SCST_DATA_BIDI) {
req->sg = scst_cmd_get_sg(scst_cmd);
req->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd);
req->bufflen = scst_cmd_get_bufflen(scst_cmd);
} else {
req->sg = scst_cmd_get_in_sg(scst_cmd);
req->sg_cnt = scst_cmd_get_in_sg_cnt(scst_cmd);
req->bufflen = scst_cmd_get_in_bufflen(scst_cmd);
}
if (unlikely(req->r2t_length > req->bufflen)) {
PRINT_ERROR("req->r2t_length %d > req->bufflen %d",
req->r2t_length, req->bufflen);
@@ -1469,23 +1543,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
goto out;
}
if (req->pdu.datasize) {
if (unlikely(dir != SCST_DATA_WRITE)) {
PRINT_ERROR("pdu.datasize(%d) >0, but dir(%x) isn't "
"WRITE", req->pdu.datasize, dir);
if (scst_get_cmd_dev_d_sense(scst_cmd))
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
sense_descr_unexpected_unsolicited_data,
sizeof(sense_descr_unexpected_unsolicited_data));
else
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
sense_fixed_unexpected_unsolicited_data,
sizeof(sense_fixed_unexpected_unsolicited_data));
cmnd_reject_scsi_cmd(req);
} else
res = cmnd_prepare_recv_pdu(conn, req, 0,
req->pdu.datasize);
}
if (req->pdu.datasize)
res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
out:
/* Aborted commands will be freed in cmnd_rx_end() */
TRACE_EXIT_RES(res);
@@ -2518,7 +2577,7 @@ static int iscsi_alloc_data_buf(struct scst_cmd *cmd)
* by the network layers. It is possible only if we
* don't use SGV cache.
*/
EXTRACHECKS_BUG_ON(scst_cmd_get_data_direction(cmd) != SCST_DATA_READ);
EXTRACHECKS_BUG_ON(!(scst_cmd_get_data_direction(cmd) & SCST_DATA_READ));
scst_cmd_set_no_sgv(cmd);
return 1;
}
@@ -2685,45 +2744,25 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
* so status is valid here, but in future that could change.
* ToDo
*/
if (status != SAM_STAT_CHECK_CONDITION) {
if ((status != SAM_STAT_CHECK_CONDITION) &&
((cmnd_hdr(req)->flags & (ISCSI_CMD_WRITE|ISCSI_CMD_READ)) !=
(ISCSI_CMD_WRITE|ISCSI_CMD_READ))) {
send_data_rsp(req, status, is_send_status);
} else {
struct iscsi_cmnd *rsp;
struct iscsi_scsi_rsp_hdr *rsp_hdr;
int resid;
send_data_rsp(req, 0, 0);
if (is_send_status) {
rsp = create_status_rsp(req, status, sense,
sense_len);
rsp_hdr =
(struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
resid = cmnd_read_size(req) - req->bufflen;
if (resid > 0) {
rsp_hdr->flags |=
ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count =
cpu_to_be32(resid);
} else if (resid < 0) {
rsp_hdr->flags |=
ISCSI_FLG_RESIDUAL_OVERFLOW;
rsp_hdr->residual_count =
cpu_to_be32(-resid);
}
iscsi_set_resid(req, rsp, true);
iscsi_cmnd_init_write(rsp,
ISCSI_INIT_WRITE_REMOVE_HASH);
}
}
} else if (is_send_status) {
struct iscsi_cmnd *rsp;
struct iscsi_scsi_rsp_hdr *rsp_hdr;
u32 resid;
rsp = create_status_rsp(req, status, sense, sense_len);
rsp_hdr = (struct iscsi_scsi_rsp_hdr *) &rsp->pdu.bhs;
resid = cmnd_read_size(req);
if (resid != 0) {
rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;
rsp_hdr->residual_count = cpu_to_be32(resid);
}
iscsi_set_resid(req, rsp, false);
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH);
}
#ifdef CONFIG_SCST_EXTRACHECKS
@@ -3095,17 +3134,6 @@ static int __init iscsi_init(void)
PRINT_INFO("iSCSI SCST Target - version %s", ISCSI_VERSION_STRING);
sense_fixed_unexpected_unsolicited_data[0] = 0x70;
sense_fixed_unexpected_unsolicited_data[2] = ABORTED_COMMAND;
sense_fixed_unexpected_unsolicited_data[7] = 6;
sense_fixed_unexpected_unsolicited_data[12] = 0xc;
sense_fixed_unexpected_unsolicited_data[13] = 0xc;
sense_descr_unexpected_unsolicited_data[0] = 0x72;
sense_descr_unexpected_unsolicited_data[1] = ABORTED_COMMAND;
sense_descr_unexpected_unsolicited_data[2] = 0xc;
sense_descr_unexpected_unsolicited_data[3] = 0xc;
dummy_page = alloc_pages(GFP_KERNEL, 0);
if (dummy_page == NULL) {
PRINT_ERROR("%s", "Dummy page allocation failed");
+3 -1
View File
@@ -30,7 +30,8 @@
#include "iscsi_dbg.h"
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x5
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x5
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0xC, 0xC
struct iscsi_sess_param {
int initial_r2t;
@@ -350,6 +351,7 @@ struct iscsi_cmnd {
struct scst_cmd *scst_cmd;
struct scst_aen *scst_aen;
};
int read_size;
};
/* Response only fields */
+117 -23
View File
@@ -1253,6 +1253,7 @@ struct scst_cmd {
/* Remote initiator supplied values, if any */
scst_data_direction expected_data_direction;
int expected_transfer_len;
int expected_in_transfer_len; /* for bidi writes */
/*
* Cmd data length. Could be different from bufflen for commands like
@@ -1266,20 +1267,25 @@ struct scst_cmd {
enum scst_exec_context pref_context);
struct sgv_pool_obj *sgv; /* sgv object */
int bufflen; /* cmd buffer length */
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
/* scst_get_sg_buf_[first,next]() support */
int get_sg_buf_entry_num;
/*
* Response data length in data buffer. This field must not be set
* directly, use scst_set_resp_data_len() for that
*/
int resp_data_len;
/* scst_get_sg_buf_[first,next]() support */
int get_sg_buf_entry_num;
/* Bidirectional transfers support */
int in_bufflen; /* WRITE buffer length */
struct sgv_pool_obj *in_sgv; /* WRITE sgv object */
struct scatterlist *in_sg; /* WRITE data buffer SG vector */
int in_sg_cnt; /* WRITE SG segments count */
/*
* Used if both target driver and dev handler request own memory
* allocation. In other cases, both are equal to sg and sg_cnt
@@ -1291,6 +1297,8 @@ struct scst_cmd {
*/
struct scatterlist *tgt_sg;
int tgt_sg_cnt;
struct scatterlist *tgt_in_sg; /* bidirectional */
int tgt_in_sg_cnt; /* bidirectional */
/*
* The status fields in case of errors must be set using
@@ -2021,25 +2029,16 @@ struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
void *data));
/*
* Translates SCST's data direction to DMA one
* Translates SCST's data direction to DMA one from backend storage
* perspective.
*/
static inline int scst_to_dma_dir(int scst_dir)
{
return scst_dir;
}
enum dma_data_direction scst_to_dma_dir(int scst_dir);
/*
* Translates SCST data direction to DMA one from the perspective
* Translates SCST data direction to DMA data direction from the perspective
* of the target device.
*/
static inline int scst_to_tgt_dma_dir(int scst_dir)
{
if (scst_dir == SCST_DATA_WRITE)
return DMA_FROM_DEVICE;
else if (scst_dir == SCST_DATA_READ)
return DMA_TO_DEVICE;
return scst_dir;
}
enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir);
/*
* Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise.
@@ -2242,6 +2241,40 @@ static inline unsigned int scst_cmd_get_bufflen(struct scst_cmd *cmd)
return cmd->bufflen;
}
/*
* Returns pointer to cmd's bidirectional in (WRITE) SG data buffer.
*
* Usage of this function is not recommended, use scst_get_in_buf_*()
* family of functions instead.
*/
static inline struct scatterlist *scst_cmd_get_in_sg(struct scst_cmd *cmd)
{
return cmd->in_sg;
}
/*
* Returns cmd's bidirectional in (WRITE) sg_cnt.
*
* Usage of this function is not recommended, use scst_get_in_buf_*()
* family of functions instead.
*/
static inline int scst_cmd_get_in_sg_cnt(struct scst_cmd *cmd)
{
return cmd->in_sg_cnt;
}
/*
* Returns cmd's bidirectional in (WRITE) data buffer length.
*
* In case if you need to iterate over data in the buffer, usage of
* this function is not recommended, use scst_get_in_buf_*()
* family of functions instead.
*/
static inline unsigned int scst_cmd_get_in_bufflen(struct scst_cmd *cmd)
{
return cmd->in_bufflen;
}
/* Returns pointer to cmd's target's SG data buffer */
static inline struct scatterlist *scst_cmd_get_tgt_sg(struct scst_cmd *cmd)
{
@@ -2263,6 +2296,28 @@ static inline void scst_cmd_set_tgt_sg(struct scst_cmd *cmd,
cmd->tgt_data_buf_alloced = 1;
}
/* Returns pointer to cmd's target's IN SG data buffer */
static inline struct scatterlist *scst_cmd_get_in_tgt_sg(struct scst_cmd *cmd)
{
return cmd->tgt_in_sg;
}
/* Returns cmd's target's IN sg_cnt */
static inline int scst_cmd_get_tgt_in_sg_cnt(struct scst_cmd *cmd)
{
return cmd->tgt_in_sg_cnt;
}
/* Sets cmd's target's IN SG data buffer */
static inline void scst_cmd_set_tgt_in_sg(struct scst_cmd *cmd,
struct scatterlist *sg, int sg_cnt)
{
WARN_ON(!cmd->tgt_data_buf_alloced);
cmd->tgt_in_sg = sg;
cmd->tgt_in_sg_cnt = sg_cnt;
}
/* Returns cmd's data direction */
static inline scst_data_direction scst_cmd_get_data_direction(
struct scst_cmd *cmd)
@@ -2443,6 +2498,12 @@ static inline int scst_cmd_get_expected_transfer_len(
return cmd->expected_transfer_len;
}
static inline int scst_cmd_get_expected_in_transfer_len(
struct scst_cmd *cmd)
{
return cmd->expected_in_transfer_len;
}
static inline void scst_cmd_set_expected(struct scst_cmd *cmd,
scst_data_direction expected_data_direction,
int expected_transfer_len)
@@ -2452,6 +2513,13 @@ static inline void scst_cmd_set_expected(struct scst_cmd *cmd,
cmd->expected_values_set = 1;
}
static inline void scst_cmd_set_expected_in_transfer_len(struct scst_cmd *cmd,
int expected_in_transfer_len)
{
WARN_ON(!cmd->expected_values_set);
cmd->expected_in_transfer_len = expected_in_transfer_len;
}
/*
* Get/clear functions for cmd's may_need_dma_sync
*/
@@ -2623,15 +2691,15 @@ static inline void sg_clear(struct scatterlist *sg)
*
* The "put" function unmaps the buffer.
*/
static inline int __scst_get_buf(struct scst_cmd *cmd, uint8_t **buf)
static inline int __scst_get_buf(struct scst_cmd *cmd, struct scatterlist *sg,
int sg_cnt, uint8_t **buf)
{
int res = 0;
struct scatterlist *sg = cmd->sg;
int i = cmd->get_sg_buf_entry_num;
*buf = NULL;
if ((i >= cmd->sg_cnt) || unlikely(sg == NULL))
if ((i >= sg_cnt) || unlikely(sg == NULL))
goto out;
*buf = page_address(sg_page(&sg[i]));
@@ -2648,12 +2716,12 @@ static inline int scst_get_buf_first(struct scst_cmd *cmd, uint8_t **buf)
{
cmd->get_sg_buf_entry_num = 0;
cmd->may_need_dma_sync = 1;
return __scst_get_buf(cmd, buf);
return __scst_get_buf(cmd, cmd->sg, cmd->sg_cnt, buf);
}
static inline int scst_get_buf_next(struct scst_cmd *cmd, uint8_t **buf)
{
return __scst_get_buf(cmd, buf);
return __scst_get_buf(cmd, cmd->sg, cmd->sg_cnt, buf);
}
static inline void scst_put_buf(struct scst_cmd *cmd, void *buf)
@@ -2661,6 +2729,23 @@ static inline void scst_put_buf(struct scst_cmd *cmd, void *buf)
/* Nothing to do */
}
static inline int scst_get_in_buf_first(struct scst_cmd *cmd, uint8_t **buf)
{
cmd->get_sg_buf_entry_num = 0;
cmd->may_need_dma_sync = 1;
return __scst_get_buf(cmd, cmd->in_sg, cmd->in_sg_cnt, buf);
}
static inline int scst_get_in_buf_next(struct scst_cmd *cmd, uint8_t **buf)
{
return __scst_get_buf(cmd, cmd->in_sg, cmd->in_sg_cnt, buf);
}
static inline void scst_put_in_buf(struct scst_cmd *cmd, void *buf)
{
/* Nothing to do */
}
/*
* Returns approximate higher rounded buffers count that
* scst_get_buf_[first|next]() return.
@@ -2670,6 +2755,15 @@ static inline int scst_get_buf_count(struct scst_cmd *cmd)
return (cmd->sg_cnt == 0) ? 1 : cmd->sg_cnt;
}
/*
* Returns approximate higher rounded buffers count that
* scst_get_in_buf_[first|next]() return.
*/
static inline int scst_get_in_buf_count(struct scst_cmd *cmd)
{
return (cmd->in_sg_cnt == 0) ? 1 : cmd->in_sg_cnt;
}
/*
* Suspends and resumes any activity.
* Function scst_suspend_activity() doesn't return 0, until there are any
+8 -5
View File
@@ -114,12 +114,14 @@ enum scst_cmd_queue_type {
};
/*************************************************************
** Data direction aliases
** Data direction aliases. Changing it don't forget to change
** scst_to_tgt_dma_dir as well!!
*************************************************************/
#define SCST_DATA_UNKNOWN 0
#define SCST_DATA_WRITE 1
#define SCST_DATA_READ 2
#define SCST_DATA_NONE 3
#define SCST_DATA_UNKNOWN 0
#define SCST_DATA_WRITE 1
#define SCST_DATA_READ 2
#define SCST_DATA_BIDI (SCST_DATA_WRITE | SCST_DATA_READ)
#define SCST_DATA_NONE 4
/*************************************************************
** Name of the "Default" security group
@@ -152,6 +154,7 @@ static inline int scst_is_ua_sense(const uint8_t *sense)
#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0
#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0
#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_reset_UA UNIT_ATTENTION, 0x29, 0
#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7
#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0
+4
View File
@@ -113,6 +113,7 @@ struct scst_user_scsi_cmd_parse {
int32_t timeout;
int32_t bufflen;
int32_t in_bufflen;
uint8_t queue_type;
uint8_t data_direction;
@@ -155,6 +156,9 @@ struct scst_user_scsi_cmd_exec {
uint8_t partial;
int32_t timeout;
aligned_u64 p_in_buf;
int32_t in_bufflen;
uint32_t sn;
uint32_t parent_cmd_h;
+34 -10
View File
@@ -510,18 +510,32 @@ static int dev_user_alloc_sg(struct scst_user_cmd *ucmd, int cached_buff)
int res = 0;
struct scst_cmd *cmd = ucmd->cmd;
struct scst_user_dev *dev = ucmd->dev;
struct sgv_pool *pool;
gfp_t gfp_mask;
int flags = 0;
int bufflen = cmd->bufflen;
int bufflen, orig_bufflen;
int last_len = 0;
int out_sg_pages = 0;
TRACE_ENTRY();
sBUG_ON(bufflen == 0);
gfp_mask = __GFP_NOWARN;
gfp_mask |= (scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL);
if (cmd->data_direction != SCST_DATA_BIDI) {
orig_bufflen = cmd->bufflen;
pool = (struct sgv_pool *)cmd->tgt_dev->dh_priv;
} else {
/* Make in_sg->offset 0 */
int len = cmd->bufflen + ucmd->first_page_offset;
out_sg_pages = (len >> PAGE_SHIFT) + ((len & ~PAGE_MASK) != 0);
orig_bufflen = (out_sg_pages << PAGE_SHIFT) + cmd->in_bufflen;
pool = dev->pool;
}
bufflen = orig_bufflen;
EXTRACHECKS_BUG_ON(bufflen == 0);
if (cached_buff) {
flags |= SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL;
if (ucmd->ubuff == 0)
@@ -534,18 +548,17 @@ static int dev_user_alloc_sg(struct scst_user_cmd *ucmd, int cached_buff)
goto out;
}
bufflen += ucmd->first_page_offset;
if (is_need_offs_page(ucmd->ubuff, cmd->bufflen))
if (is_need_offs_page(ucmd->ubuff, orig_bufflen))
last_len = bufflen & ~PAGE_MASK;
else
last_len = cmd->bufflen & ~PAGE_MASK;
last_len = orig_bufflen & ~PAGE_MASK;
if (last_len == 0)
last_len = PAGE_SIZE;
}
ucmd->buff_cached = cached_buff;
cmd->sg = sgv_pool_alloc((struct sgv_pool *)cmd->tgt_dev->dh_priv,
bufflen, gfp_mask, flags, &cmd->sg_cnt, &ucmd->sgv,
&dev->udev_mem_lim, ucmd);
cmd->sg = sgv_pool_alloc(pool, bufflen, gfp_mask, flags, &cmd->sg_cnt,
&ucmd->sgv, &dev->udev_mem_lim, ucmd);
if (cmd->sg != NULL) {
struct scst_user_cmd *buf_ucmd =
(struct scst_user_cmd *)sgv_get_priv(ucmd->sgv);
@@ -569,14 +582,21 @@ static int dev_user_alloc_sg(struct scst_user_cmd *ucmd, int cached_buff)
"last seg len %d)", ucmd, cached_buff, ucmd->ubuff,
cmd->sg[cmd->sg_cnt-1].length);
if (cmd->data_direction == SCST_DATA_BIDI) {
cmd->in_sg = &cmd->sg[out_sg_pages];
cmd->in_sg_cnt = cmd->sg_cnt - out_sg_pages;
cmd->sg_cnt = out_sg_pages;
TRACE_MEM("cmd %p, in_sg %p, in_sg_cnt %d, sg_cnt %d",
cmd, cmd->in_sg, cmd->in_sg_cnt, cmd->sg_cnt);
}
if (unlikely(cmd->sg_cnt > cmd->tgt_dev->max_sg_cnt)) {
static int ll;
if (ll < 10) {
PRINT_INFO("Unable to complete command due to "
"SG IO count limitation (requested %d, "
"available %d, tgt lim %d)",
cmd->sg_cnt,
cmd->tgt_dev->max_sg_cnt,
cmd->sg_cnt, cmd->tgt_dev->max_sg_cnt,
cmd->tgt->sg_tablesize);
ll++;
}
@@ -771,6 +791,7 @@ static int dev_user_parse(struct scst_cmd *cmd)
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.in_bufflen = cmd->in_bufflen;
ucmd->user_cmd.parse_cmd.queue_type = cmd->queue_type;
ucmd->user_cmd.parse_cmd.data_direction = cmd->data_direction;
ucmd->user_cmd.parse_cmd.expected_values_set =
@@ -903,6 +924,9 @@ static int dev_user_exec(struct scst_cmd *cmd)
ucmd->user_cmd.exec_cmd.data_direction = cmd->data_direction;
ucmd->user_cmd.exec_cmd.partial = 0;
ucmd->user_cmd.exec_cmd.timeout = cmd->timeout / HZ;
ucmd->user_cmd.exec_cmd.p_in_buf = ucmd->ubuff +
(cmd->sg_cnt << PAGE_SHIFT);
ucmd->user_cmd.exec_cmd.in_bufflen = cmd->in_bufflen;
ucmd->user_cmd.exec_cmd.sn = cmd->tgt_sn;
ucmd->state = UCMD_STATE_EXECING;
+62 -16
View File
@@ -156,23 +156,42 @@ EXPORT_SYMBOL(scst_set_cmd_error);
void scst_set_sense(uint8_t *buffer, int len, bool d_sense,
int key, int asc, int ascq)
{
sBUG_ON(len < SCST_STANDARD_SENSE_LEN);
sBUG_ON(len == 0);
memset(buffer, 0, len);
if (d_sense) {
/* Descriptor format */
buffer[0] = 0x72; /* Response Code */
buffer[1] = key; /* Sense Key */
buffer[2] = asc; /* ASC */
buffer[3] = ascq; /* ASCQ */
if (len < 4) {
PRINT_ERROR("Length %d of sense buffer too small to "
"fit sense %x:%x:%x", len, key, asc, ascq);
}
buffer[0] = 0x72; /* Response Code */
if (len > 1)
buffer[1] = key; /* Sense Key */
if (len > 2)
buffer[2] = asc; /* ASC */
if (len > 3)
buffer[3] = ascq; /* ASCQ */
} else {
/* Fixed format */
buffer[0] = 0x70; /* Response Code */
buffer[2] = key; /* Sense Key */
buffer[7] = 0x0a; /* Additional Sense Length */
buffer[12] = asc; /* ASC */
buffer[13] = ascq; /* ASCQ */
if (len < 14) {
PRINT_ERROR("Length %d of sense buffer too small to "
"fit sense %x:%x:%x", len, key, asc, ascq);
}
buffer[0] = 0x70; /* Response Code */
if (len > 2)
buffer[2] = key; /* Sense Key */
if (len > 7)
buffer[7] = 0x0a; /* Additional Sense Length */
if (len > 12)
buffer[12] = asc; /* ASC */
if (len > 13)
buffer[13] = ascq; /* ASCQ */
}
TRACE_BUFFER("Sense set", buffer, len);
@@ -652,6 +671,8 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
break;
default:
PRINT_CRIT_ERROR("Wrong cmd state %d (cmd %p, op %x)",
cmd->state, cmd, cmd->cdb[0]);
sBUG();
}
@@ -666,12 +687,11 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd)
#ifdef CONFIG_SCST_EXTRACHECKS
switch (cmd->state) {
case SCST_CMD_STATE_PRE_XMIT_RESP:
case SCST_CMD_STATE_XMIT_RESP:
case SCST_CMD_STATE_FINISHED:
case SCST_CMD_STATE_FINISHED_INTERNAL:
case SCST_CMD_STATE_XMIT_WAIT:
PRINT_CRIT_ERROR("Wrong cmd state %x (cmd %p, op %x)",
PRINT_CRIT_ERROR("Wrong cmd state %d (cmd %p, op %x)",
cmd->state, cmd, cmd->cdb[0]);
sBUG();
}
@@ -2258,10 +2278,18 @@ void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir)
TRACE_ENTRY();
if (copy_dir == SCST_SG_COPY_FROM_TARGET) {
src_sg = cmd->tgt_sg;
src_sg_cnt = cmd->tgt_sg_cnt;
dst_sg = cmd->sg;
to_copy = cmd->bufflen;
if (cmd->data_direction != SCST_DATA_BIDI) {
src_sg = cmd->tgt_sg;
src_sg_cnt = cmd->tgt_sg_cnt;
dst_sg = cmd->sg;
to_copy = cmd->bufflen;
} else {
TRACE_MEM("BIDI cmd %p", cmd);
src_sg = cmd->tgt_in_sg;
src_sg_cnt = cmd->tgt_in_sg_cnt;
dst_sg = cmd->in_sg;
to_copy = cmd->in_bufflen;
}
} else {
src_sg = cmd->sg;
src_sg_cnt = cmd->sg_cnt;
@@ -3099,6 +3127,24 @@ static void scst_check_internal_sense(struct scst_device *dev, int result,
return;
}
enum dma_data_direction scst_to_dma_dir(int scst_dir)
{
static const enum dma_data_direction tr_tbl[] = { DMA_NONE,
DMA_TO_DEVICE, DMA_FROM_DEVICE, DMA_BIDIRECTIONAL, DMA_NONE };
return tr_tbl[scst_dir];
}
EXPORT_SYMBOL(scst_to_dma_dir);
enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir)
{
static const enum dma_data_direction tr_tbl[] = { DMA_NONE,
DMA_FROM_DEVICE, DMA_TO_DEVICE, DMA_BIDIRECTIONAL, DMA_NONE };
return tr_tbl[scst_dir];
}
EXPORT_SYMBOL(scst_to_tgt_dma_dir);
int scst_obtain_device_parameters(struct scst_device *dev)
{
int res = 0, i;
-5
View File
@@ -1691,11 +1691,6 @@ static int __init init_scst(void)
BUILD_BUG_ON(sizeof(c->sn) != sizeof(t->expected_sn));
}
BUILD_BUG_ON(SCST_DATA_UNKNOWN != DMA_BIDIRECTIONAL);
BUILD_BUG_ON(SCST_DATA_WRITE != DMA_TO_DEVICE);
BUILD_BUG_ON(SCST_DATA_READ != DMA_FROM_DEVICE);
BUILD_BUG_ON(SCST_DATA_NONE != DMA_NONE);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
#if !defined(SCST_IO_CONTEXT)
PRINT_WARNING("%s", "Patch io_context was not applied on "
+55 -43
View File
@@ -135,7 +135,7 @@ static int scst_init_cmd(struct scst_cmd *cmd, enum scst_exec_context *context)
(*context == SCST_CONTEXT_DIRECT_ATOMIC) ||
((*context == SCST_CONTEXT_SAME) && scst_cmd_atomic(cmd))) &&
scst_cmd_is_expected_set(cmd)) {
if (cmd->expected_data_direction == SCST_DATA_WRITE) {
if (cmd->expected_data_direction & SCST_DATA_WRITE) {
if (!test_bit(SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC,
&cmd->tgt_dev->tgt_dev_flags))
*context = SCST_CONTEXT_THREAD;
@@ -290,6 +290,9 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
if (unlikely(rc < 0))
goto out;
if (unlikely(cmd->status != SAM_STAT_GOOD))
scst_set_cmd_abnormal_done_state(cmd);
active:
/* Here cmd must not be in any cmd list, no locks */
switch (pref_context) {
@@ -664,7 +667,7 @@ set_res:
}
if (cmd->resp_data_len == -1) {
if (cmd->data_direction == SCST_DATA_READ)
if (cmd->data_direction & SCST_DATA_READ)
cmd->resp_data_len = cmd->bufflen;
else
cmd->resp_data_len = 0;
@@ -728,17 +731,15 @@ static int scst_prepare_space(struct scst_cmd *cmd)
alloc:
if (!cmd->tgt_data_buf_alloced && !cmd->dh_data_buf_alloced) {
r = scst_alloc_space(cmd);
cmd->tgt_sg = cmd->sg;
cmd->tgt_sg_cnt = cmd->sg_cnt;
} else if (cmd->dh_data_buf_alloced && !cmd->tgt_data_buf_alloced) {
TRACE_MEM("dh_data_buf_alloced set (cmd %p)", cmd);
cmd->tgt_sg = cmd->sg;
cmd->tgt_sg_cnt = cmd->sg_cnt;
r = 0;
} else if (cmd->tgt_data_buf_alloced && !cmd->dh_data_buf_alloced) {
TRACE_MEM("tgt_data_buf_alloced set (cmd %p)", cmd);
cmd->sg = cmd->tgt_sg;
cmd->sg_cnt = cmd->tgt_sg_cnt;
cmd->in_sg = cmd->tgt_in_sg;
cmd->in_sg_cnt = cmd->tgt_in_sg_cnt;
r = 0;
} else {
TRACE_MEM("Both *_data_buf_alloced set (cmd %p, sg %p, "
@@ -778,15 +779,10 @@ prep_done:
}
switch (cmd->data_direction) {
case SCST_DATA_WRITE:
if (cmd->data_direction & SCST_DATA_WRITE)
cmd->state = SCST_CMD_STATE_RDY_TO_XFER;
break;
default:
else
cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
break;
}
out:
TRACE_EXIT_HRES(res);
@@ -830,14 +826,10 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
switch (status) {
case SCST_PREPROCESS_STATUS_SUCCESS:
switch (cmd->data_direction) {
case SCST_DATA_WRITE:
if (cmd->data_direction & SCST_DATA_WRITE)
cmd->state = SCST_CMD_STATE_RDY_TO_XFER;
break;
default:
else
cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
break;
}
if (cmd->set_sn_on_restart_cmd)
scst_cmd_set_sn(cmd);
/* Small context optimization */
@@ -845,7 +837,7 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
(pref_context == SCST_CONTEXT_DIRECT_ATOMIC) ||
((pref_context == SCST_CONTEXT_SAME) &&
scst_cmd_atomic(cmd))) {
if (cmd->data_direction == SCST_DATA_WRITE) {
if (cmd->data_direction & SCST_DATA_WRITE) {
if (!test_bit(SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC,
&cmd->tgt_dev->tgt_dev_flags))
pref_context = SCST_CONTEXT_THREAD;
@@ -865,8 +857,9 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
/* go through */
case SCST_PREPROCESS_STATUS_ERROR:
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
if (cmd->sense != NULL)
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
scst_set_cmd_abnormal_done_state(cmd);
break;
@@ -1097,15 +1090,26 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
switch (status) {
case SCST_RX_STATUS_SUCCESS:
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
if (cmd->tgt_sg) {
if (trace_flag & TRACE_RCV_BOT) {
int i;
struct scatterlist *sg = cmd->tgt_sg;
TRACE_RECV_BOT("RX data for cmd %p "
"(sg_cnt %d, sg %p, sg[0].page %p)", cmd,
cmd->tgt_sg_cnt, sg, (void *)sg_page(&sg[0]));
for (i = 0; i < cmd->tgt_sg_cnt; ++i) {
PRINT_BUFF_FLAG(TRACE_RCV_BOT, "RX sg",
sg_virt(&sg[i]), sg[i].length);
struct scatterlist *sg;
if (cmd->in_sg != NULL)
sg = cmd->in_sg;
else if (cmd->tgt_in_sg != NULL)
sg = cmd->tgt_in_sg;
else if (cmd->tgt_sg != NULL)
sg = cmd->tgt_sg;
else
sg = cmd->sg;
if (sg != NULL) {
TRACE_RECV_BOT("RX data for cmd %p "
"(sg_cnt %d, sg %p, sg[0].page %p)",
cmd, cmd->tgt_sg_cnt, sg,
(void *)sg_page(&sg[0]));
for (i = 0; i < cmd->tgt_sg_cnt; ++i) {
PRINT_BUFF_FLAG(TRACE_RCV_BOT, "RX sg",
sg_virt(&sg[i]), sg[i].length);
}
}
}
#endif
@@ -1355,7 +1359,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state,
#if defined(CONFIG_SCST_DEBUG)
if (next_state == SCST_CMD_STATE_PRE_DEV_DONE) {
if (cmd->sg) {
if ((trace_flag & TRACE_RCV_TOP) && (cmd->sg != NULL)) {
int i;
struct scatterlist *sg = cmd->sg;
TRACE_RECV_TOP("Exec'd %d S/G(s) at %p sg[0].page at "
@@ -2140,7 +2144,7 @@ static int scst_exec(struct scst_cmd **active_cmd)
cmd->state = SCST_CMD_STATE_LOCAL_EXEC;
if (cmd->tgt_data_buf_alloced && cmd->dh_data_buf_alloced &&
(cmd->data_direction == SCST_DATA_WRITE))
(cmd->data_direction & SCST_DATA_WRITE))
scst_copy_sg(cmd, SCST_SG_COPY_FROM_TARGET);
rc = scst_do_local_exec(cmd);
@@ -2774,7 +2778,7 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count);
atomic_dec(&cmd->dev->dev_cmd_count);
/* If expected values not set, expected direction is UNKNOWN */
if (cmd->expected_data_direction == SCST_DATA_WRITE)
if (cmd->expected_data_direction & SCST_DATA_WRITE)
atomic_dec(&cmd->dev->write_cmd_count);
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
@@ -2816,7 +2820,7 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
}
if (cmd->tgt_data_buf_alloced && cmd->dh_data_buf_alloced &&
(cmd->data_direction == SCST_DATA_READ))
(cmd->data_direction & SCST_DATA_READ))
scst_copy_sg(cmd, SCST_SG_COPY_TO_TARGET);
cmd->state = SCST_CMD_STATE_XMIT_RESP;
@@ -2883,15 +2887,23 @@ static int scst_xmit_response(struct scst_cmd *cmd)
TRACE_DBG("Calling xmit_response(%p)", cmd);
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
if (cmd->tgt_sg) {
if (trace_flag & TRACE_SND_BOT) {
int i;
struct scatterlist *sg = cmd->tgt_sg;
TRACE(TRACE_SND_BOT, "Xmitting data for cmd %p "
"(sg_cnt %d, sg %p, sg[0].page %p)", cmd,
cmd->tgt_sg_cnt, sg, (void *)sg_page(&sg[0]));
for (i = 0; i < cmd->tgt_sg_cnt; ++i) {
PRINT_BUFF_FLAG(TRACE_SND_BOT, "Xmitting sg",
sg_virt(&sg[i]), sg[i].length);
struct scatterlist *sg;
if (cmd->tgt_sg != NULL)
sg = cmd->tgt_sg;
else
sg = cmd->sg;
if (sg != NULL) {
TRACE(TRACE_SND_BOT, "Xmitting data for cmd %p "
"(sg_cnt %d, sg %p, sg[0].page %p)",
cmd, cmd->tgt_sg_cnt, sg,
(void *)sg_page(&sg[0]));
for (i = 0; i < cmd->tgt_sg_cnt; ++i) {
PRINT_BUFF_FLAG(TRACE_SND_BOT,
"Xmitting sg", sg_virt(&sg[i]),
sg[i].length);
}
}
}
#endif
@@ -3235,7 +3247,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
}
/* If expected values not set, expected direction is UNKNOWN */
if (cmd->expected_data_direction == SCST_DATA_WRITE)
if (cmd->expected_data_direction & SCST_DATA_WRITE)
atomic_inc(&cmd->dev->write_cmd_count);
if (unlikely(failure))
+15 -9
View File
@@ -494,23 +494,32 @@ static int scst_local_queuecommand(struct scsi_cmnd *SCpnt,
switch (SCpnt->sc_data_direction) {
case DMA_TO_DEVICE:
dir = SCST_DATA_WRITE;
scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
scst_cmd_set_tgt_sg(scst_cmd, scsi_sglist(SCpnt),
scsi_sg_count(SCpnt));
break;
case DMA_FROM_DEVICE:
dir = SCST_DATA_READ;
scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
scst_cmd_set_tgt_sg(scst_cmd, scsi_sglist(SCpnt),
scsi_sg_count(SCpnt));
break;
case DMA_BIDIRECTIONAL:
printk(KERN_ERR "%s: DMA_BIDIRECTIONAL not allowed!\n",
__func__);
return scst_local_send_resp(SCpnt, NULL, done,
DID_ERROR << 16);
/*dir = SCST_DATA_UNKNOWN;*/
dir = SCST_DATA_BIDI;
scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
scst_cmd_set_expected_in_transfer_len(scst_cmd,
scsi_in(SCpnt)->length);
scst_cmd_set_tgt_sg(scst_cmd, scsi_sglist(SCpnt),
scsi_sg_count(SCpnt));
scst_cmd_set_tgt_in_sg(scst_cmd, scsi_in(SCpnt)->table.sgl,
scsi_in(SCpnt)->table.nents);
break;
case DMA_NONE:
default:
dir = SCST_DATA_NONE;
scst_cmd_set_expected(scst_cmd, dir, 0);
break;
}
scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
/*
* Defer allocating memory until all error paths are done
@@ -526,9 +535,6 @@ static int scst_local_queuecommand(struct scsi_cmnd *SCpnt,
scst_cmd_set_tgt_priv(scst_cmd, tgt_specific);
/* Set the SGL things directly ... */
scst_cmd_set_tgt_sg(scst_cmd, scsi_sglist(SCpnt), scsi_sg_count(SCpnt));
#ifdef CONFIG_SCST_LOCAL_FORCE_DIRECT_PROCESSING
{
struct Scsi_Host *h = SCpnt->device->host;