mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-19 22:42:38 +00:00
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:
+15
-1
@@ -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
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user